Page MenuHomePhorge

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/CHANGELOG b/CHANGELOG
index 96efc1bbc..43cc834a9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,7474 +1,7508 @@
-2.7.6rc2
+2.7.6 (includes CVE-2011-3872 see http://puppetlabs.com/security/hotfixes/cve-2011-3872/
===
+c09517a Improve the error message when a CSR is rejected
+9346530 Allow a master to bootstrap itself with dns_alt_names and autosign
+7679c66 (maint) Remove ssl dir before starting a master with DNS alt names
+e4c64c7 Fix failing CA Interface specs on Ruby 1.9
+9ee1215 Fix some inconsistencies from merging
+8144939 Add support for DNS alt names to `puppet ca`
+2ba56e3 More 1.8.5 compatibility fixes.
+6257188 Better 1.8.5 compatible implementation of `lines`.
+4ba4db7 (#2848) Config options require '_', not '-'.
+493f8d1 Add --allow-dns-alt-names option to `puppet certificate sign`
+0cc8936 Add support for dns-alt-names option to `puppet certificate generate`
+c65236d Ruby 1.8.5 compatibility changes in tests and code.
+6c37623 Add `lines` alias for `each_line` in Ruby 1.8.5.
+e29eb6a s/not_to/should_not/ for older versions of RSpec 2.
+f1f5298 (#2848) Eliminate redundant `master_dns_alt_names`.
+3a8b376 (#2848) Remove the legacy SSLCertificates code
+28dead0 (#2848) Rework the xmlrpc CA handler to use the modern SSL code
+a644514 (#2848) Remove unused xmlrpc code
+2b1ad43 (#2848) Consistent return values from `subject_alt_names` accessors.
+d8516d9 (#2848) Consistently use `subject_alt_names` as accessor name.
+0b45f4c (#2848) Don't strip the subjectAltName label when listing.
+99488f3 (#2848) Don't enable `emailProtection` for server keys.
+f1285a4 (#2848) Only mark `subjectAltName` critical if `subject` is empty.
+e65a88e (#2848) Migrate `dns-alt-names` back to settings.
+b876c39 Wire up the `setbycli` slot in Puppet settings.
+a53f2f2 (#2848) rename subject-alt-name option to dns-alt-names
+bc2267a (#2848) Rename `certdnsnames` to match new behaviour.
+a720499 (#2848) Use `certdnsnames` when bootstrapping a local master.
+6e3f529 (#2848) CSR subjectAltNames handling while signing.
+978b65c (#2848) List subject alt names in output of puppet cert --list
+7460a5e (#7224) Add a helper to Puppet::SSL::Certificate to retrieve alternate names
+94345eb (#2848) Rewrite SSL Certificate Factory, fixing `subjectAltName` leak.
+a729d90 (#2848) Reject unknown (== all) extensions on the CSR.
+f4fc11d (#2848) extract the subjectAltName value from the CSR.
+d64b01b (#2848) Set `certdnsnames` values into the CSR.
+78a01a2 (#6928) Don't blow up when the method is undefined...
+43d1e38 (#9996) Restore functionality for multi-line commands in exec resources
d457763 (#9832) General StoreConfigs regression.
-
-2.7.6rc1
-===
2958b05 maint: Deal with [].to_s problem in 1.9.2
9c25af4 (#9027) Get rid of spurious info messages in groupadd
1f25c20 (#8411) Fix change group for POSIX file provider
599642d Fix problem with set_mode (chmod) behavior on different test environments.
b43765d Undo change to failing test on 1.8.5
c275a51 Resist directory traversal attacks through indirections.
d759f84 (#9838) Return the tranaction report when doing a ral save
127f83e (#9837) Split parameter pruning from manifest formatting
9d5ce00 (#9837) Move resource formatting method to Puppet::Resource
86230d8 (#9837) Move properties in prep to move proc to method
bf952e1 (#9837) Make a clearer variable name in the specs
6885c36 (#9837) Call puppet apply to avoid deprecation warning
93f8057 (#9837) Extract methods from the main section of the resource application
5d33214 (#9837) Start the cleanup of the puppet resource application
54a2565 (#9832) Test failures with some ActiveRecord versions.
2bf8004 Updates for 2.6.11
8343077 (#9832) 2.7.4 StoreConfigs regression with PostgreSQL.
dce82ea (#9458) Require main puppet module
e158b26 (#9793) "secure" indirector file backed terminus base class.
343c7bd (#9792) Predictable temporary filename in ralsh.
88512e8 Drop privileges before creating and chmodding SSH keys.
6533292 (#9328) Retrieve user and group SIDs on windows.
2775c21 (#9794) k5login can overwrite arbitrary files as root
e7a6995 (#9794) k5login can overwrite arbitrary files as root
408d117 Updated CHANGELOG for 2.6.10
ec5a32a Update spec and lib/puppet.rb for 2.6.10 release
4e8d3a1 (#9775) Only list managed resources in the resources file
51b33d1 (#9326) Support plaintext passwords in Windows 'user' provider.
fe2de81 Resist directory traversal attacks through indirections.
5fea1dc Fix issues with Windows based file URIs
1a13d24 Simplify absolute path detection
a163cd5 Eliminate duplicate absolute path detection
0ce60a5 Added methods for manipulating URI and file paths
71ba92c Restrict the absolute path regex to the start of the string
1edf767 Move group management into providers
15149c1 Remove duplicate SID resolution code
f932511 Move owner management into providers
f05fc83 Add platform-specific metadata collectors
db0b4fb Make string_to_sid_ptr block optional
7fc6baf Add the ability to retrieve user and group SIDs
22bfd9c Move mode management into the providers
4c3aae8 Fix typo bug that prevented FILE_DELETE_CHILD from being set
7de0a80 Sub away trailing backslashes at the end of sources on Windows
44cb1f1 Refactor autorequire of parent to use pathname with ancestors
1300e0a Remove unnecessary Windows-on-non-Windows-master code for path parameter
1f9b57f Cleanup file type integration tests
8d21262 Cleanup and improve coverage of file type unit tests
0a92a70 Resist directory traversal attacks through indirections.
8b6a775 Call Array#join explicitly on command
ae74c68 Fix failing SSL Host test introduced by b6a67edc
37a1975 (#4549) Fix templates to be able to call all functions
a74e56d Expand paths in catalog_spec for windows testing
8d86e5a (9547) Minor mods to acceptance tests
8ec3c7b (#4135) Update pluginsync to only load ruby files.
0c8a0c7 Fix order dependent test failures relating to ADSI
c0edb76 (#9186) Fix tests that fail on 2008 when running as SYSTEM
8e14de6 (#9186) Handle when running under non 'user' contexts
7595475 Fix device.conf error reporting
1d3a3a7 Fix #9164 - allow '-' in device certificate names
b6a67ed Fix #7982 - puppet device doesn't reset all cached attributes
ba1f469 (#9186) Change to shared_examples_for
b27b013 (#8410) Fix child exit status on Windows
42c9982 (#9186) Add the ability to get/set windows permissions
d34d28d (#9435) Gracefully handle when syslog feature is unavailable
f013c65 (#9435) Fix absolute path matching for file log destinations
ea88745 (#9329) Disable agent daemonizing on Windows
2.7.5
===
a36f39d Updating version numbers for 2.7.5
de51f3d (#9832) 2.7.4 StoreConfigs regression with PostgreSQL.
1aa9be5 (#9793) "secure" indirector file backed terminus base class.
d76c309 (#9792) Predictable temporary filename in ralsh. (CVE-2011-3871)
b29b178 Drop privileges before creating and chmodding SSH keys.(CVE-2011-3870)
7d4c169 (#9794) k5login can overwrite arbitrary files as root (CVE-2011-3869)
2.7.4
===
47135fb Resist directory traversal attacks through indirections. (CVE-2011-3484)
9dd18cf Updated CHANGELOG for 2.7.4rc3
fe92f20 (#9440) Allow cron vars to have leading whitespace
da69637 Fix failing spec for resource file
7a39ca7 (#8667) Write out a list of resources that are managed by puppet agent
bc40516 Fix order dependent spec failure in exec specs
a20551f Updated CHANGELOG for 2.7.4rc2
d59a0b3 Update certificate_spec.rb test to include spec_helper
f325b40 Fix #7984 - GigabitEthernet/TenGigabitEthernet are uncorrectly parsed
6cc15c2 Fix #7983 - Cisco uptime facts doesn't always work
41302e9 Fixes #9143, allows macauthorization provider to work on OS X Lion 10.7
5a3f24d Updated CHANGELOG for 2.7.4rc1
04519a7 Revert "Merge pull request #100 from glarizza/tickets/2.7.x/9192_launchd_fix"
769f2b2 Revert "Merge pull request #99 from nigelkersten/tickets/2.7.x/9143-make-macauthorization-work-on-lion"
ff13d8d Add comment explaining helper method
40f64e9 Add has_macosx_plist_overrides? method
670d30c Fix ActiveRecord handling of symbols in query interpolation.
51b0c00 Fixes #9143, allows macauthorization provider to work on OS X Lion 10.7
a04051a (#9051) Move complex collect expression error into terminus.
f7e526b (#8413) Only try to catch Process::Error if it's defined
2c96286 Debug order-dependent test failures in CI / ActiveRecord.
38070d5 Don't toggle storeconfigs back and forth.
cf60243 One character typo, entire code path broken...
40dc39c More protection against accidentally using sqlite3
f898749 Save and restore indirector configuration around all tests.
e3073ac (#9051) More storeconfigs test cleanup.
51461de (#9051) Protect SQLite tests from running without gem.
bb0380f (#8662) Don't rely on error message to detect UAC capable platform
2ab5634 (#8413) Properly clean up stale pidfile on Windows
cc958e1 (#8412) Add MSI package provider for use with Windows
878ea25 (#8412) Add optional type-level validation of the source parameter
dad075d Correct grammar in parameter comment
4168a4c Clean up formatting & whitespace in Puppet::Type
fd1d4b9 (#9051) de-ActiveRecord-ify Collection expressions.
78e33cc (#9051) Port query tests into the indirection.
65580e7 (#9051) Implement the `resource` terminus for StoreConfigs.
89aaa51 (#9051) Make generic tagging imported resource origins.
d5b295d (#9051) Whitespace cleanup for puppet/parser/collector
611c466 (#9051) Dead code elimination in the compiler terminus.
6e0ff6a (#9051) Get the compiler out of the ActiveRecord business.
4d51680 (#9051) Implement the StoreConfigs indirection itself.
d0357c8 (#9051) Add configuration around StoreConfigs indirection.
8700682 (#9051) de-ActiveRecord-ify Collection expressions.
4274e15 (#9174) Provide a helpful error when missing a gem and installing on Windows
f53db3d Clean up formatting & whitespace in package type & providers
6dff78c (#8489) Use File::PATH_SEPARATOR in path attribute of service type
64dbd3b (#8489) Use File::PATH_SEPARATOR for path attribute of exec type
3e40207 (#8489) Use File::PATH_SEPARATOR rather than ':' for factpath setting
c469294 (#8489) Use File::PATH_SEPARATOR rather than ':' for args to puppet doc
a2ced0f Properly determine file deletion in puppet/unit/util_spec.rb
bc5f1e3 (#9051) Port query tests into the indirection.
fa78e99 (#9051) Implement the `resource` terminus for StoreConfigs.
f6b91be (#8140) Add an exec provider for Windows
18c322a (#8410) Factor out a base class for exec providers
cb53870 (#8410) Cleanup and fix Windows support in Puppet::Util.execute
39a582b (#8410) Use absolute_path? for Puppet::Parameter::Path validation
fb6df31 (#8410) Add a helper to Puppet::Util to determine absoluteness of a path
c2a432a maint: Fix trailing whitespace in lib/puppet/util.rb
fab2fe7 (#9051) Make generic tagging imported resource origins.
5300368 (#9051) Whitespace cleanup for puppet/parser/collector
6420ede (#9051) Dead code elimination in the compiler terminus.
543f331 (#9051) Get the compiler out of the ActiveRecord business.
4b55e72 (#9051) Implement the StoreConfigs indirection itself.
0f207a8 (#8662) Don't manage internal file permissions on Windows
47058ab (#8662) Skip user and group resources when applying settings on Windows
2ac8790 (#8662) Fix Puppet.features.root? on Windows
ccdd043 (#8662) Break circular feature dependency
4b29f5f (#9051) Add configuration around StoreConfigs indirection.
9f39cc4 maint: Stub spec test so directory is not created unnecessarily
66fb531 Don't use non-1.8.5-compatible methods 'Object#tap' and 'Dir.mktmpdir'
2091cbe maint: Fix build break due to recent merge from 2.7.x to master
2681ca5 Fix posix exec provider spec failures on Windows
3812fc3 (#5495) Remove dead Windows-specific code from posix exec provider
b6ca78c Stop trying to make config directories in Windows specs
4237cb1 (#8272) Add missing tests for Windows service provider methods.
a32c8be (#8409) Add a default group provider for Windows
4f7170a (#8408) Add a default user provider for Windows
f19a0ea (#8408/8409) Add a Windows ADSI helper module
6919d2c (#8663) Exclude exec timeout test on Windows
8009209 (#8663) Exclude git rev-parse HEAD spec test on Windows
a0013e4 Check for the appropriate permissions in File type tests on Windows
58c7dac Remove :fails_on_windows from file type tests that no longer fail on Windows
9f2a7b9 Disable file bucket diffing tests on Windows
1e59b26 Always put a slash between the checksum and path in filebucket URLs
37f87b7 Treat Windows absolute paths as absolute paths
4a6d617 Consolidate test logic determining if a registered file is in the temp directory
8c88918 Clarify logic and error messages when initializing Puppet::FileBucket::File
2efaa85 Disable symlink related file tests on Windows
7259e1e (#8644) Host provider on Windows
328eaa2 (#8660) Fix destdir option on Windows
088c7ac (#8660) Default config dir to %PROGRAMDATA% on Windows
925af95 (#8663) Disable spec tests for unsupported functionality on Windows
04965d7 (#8663) Drive letters are not valid absolute paths on Windows
f4598ec (#8663) Update the run_mode spec test on Windows to match the code
68bdc74 (#8663) The ssh_authorized_key type is not supported on Windows
9fbb0be (#8663) Reenable spec tests on Windows that now pass
c930152 (#8392) Disable master related tests on Windows
28b1658 (#8272) Allow disabled Windows services to be started
c69baf6 (#8272) Refactor specs for Windows service provider
881c385 (#8272) Use symbols instead of booleans for enabled property on Windows
9c575bd (#8272) Fixup logging in Windows service provider
ad29bf6 Fix issue with forward and backslashes in Windows paths
eaa7d92 Disable spec tests for unsupported functionality on Windows
945bf74 Update certificate spec tests for Windows
3be4d79 Add basic service provider for Windows
d9a693d Regexp escape substituted commands in Windows wrapper script
49d1e9d Rework Puppet::Util::Cacher to only expire using TTLs
9849d56 Remove use of Puppet::Util::Cacher in Puppet::SSL::Host
028b795 Remove dead uses of Puppet::Util::Cacher from autoloader
7c4dbeb Remove Puppet::Util::Cacher use from Puppet::Indirector::Indirection
d6e0b71 Remove caching from the catalog, types, and parameters
d49dd9e Remove cached_attrs from Puppet::Type::File
546e0f9 Remove Puppet::Util::Cacher usage from Puppet::Util::Settings
b6b5498 Remove Util::Cacher usage from SSL::CertificateAuthority
777b2f2 Remove unused require 'puppet/util/cacher' from Network::HttpPool
41425bd Remove use of Util::Cacher from FileServing::Mount::File
8d53090 Remove use of Util::Cacher in FileServing::Configuration
3093047 Remove Puppet::Network::HttpPool keep_alive handling
57d6217 Fix spec test failure on 1.9.2
5d3a40f Maint: Fix miscellaneous tests
ce0c258 Maint: Don't test for extended signals on Windows
bdc9790 Maint: Tagged spec tests that are known to fail on Windows
c26f3e5 Fix tests with "relative" paths on Windows
bfeb337 (#8268) Require windows drive letters in absolute file paths
fe81dec (#8489) Consistently use File::PATH_SEPARATOR
a437812 (#8356) Specify setting type for color
af2446a (#8268) Fix resource harness spec tests
d9c3b0f (#8356) Color defaults to false on Windows
9ebe500 Disable the master on Windows instead of blowing up with failed resources
7467a08 (#7581) Provide more detailed error message when missing gems on Windows
654de01 Maint: Correct docs for filebucket type and file's backup parameter
b623826 Maint: Fix line wrapping in create_resources function
fd7332b maint: remove inaccurate copyright and license statements.
a8b27de Maint: Improve create_resources function's doc string
5f22985 maint: Fix order dependent test failure
7ac1093 (#8037) Fix incorrect example in Augeas type reference
35c1006 (#9039) Update Augeas commands documentation
2bf6721 Reset indirector state after configurer tests.
e9b558d Fix posix exec provider spec failures on Windows
b28bcb0 (#5495) Remove dead Windows-specific code from posix exec provider
2297899 Do not leak indirector state from apply tests
b52fbf4 (#8612) Clarify the function of the example for exec's "creates" parameter
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.
39da99d (#4411) Explain that runinterval = 0 does not mean "never run"
4146a33 Maint: Fix missing option text in puppet agent and arrange options alphabetically
0e00473 (#3553) Explain that cron resources require time attributes
769d432 (#8302) Improve documentation of exec providers
76d45d2 (#7853) Clarify and complete docs for the tagmail report processor
d60852b Maint: Mention that audit metaparameter will accept "all"
51d989e Maint: Adjust wording for file type's content parameter
a110d83 Maint: Fix poor documentation for versioncmp function.
746a374 maint: Fix case sensitive require
310bd55 maint: Add inspect app options to help
3a19628 maint: Fix inspect help
344aef9 (#8808) Fail Augeas resource when unable to save changes
c209f62 Add document outlining preferred contribution methods
839e7c9 (#7999) Add some basic tests of the systemd provider
1cae354 (#7999) Add a service provider that manages systemd services natively
3b152e4 (#7114) Fix value validation on options
aa1b36f (#7114) Add tests for option property
2.7.3
===
7113448 (#4762) Ensure that clients on the moon can successfully connect.
c8835ad Add document outlining preferred contribution methods
b85f57c Add document outlining preferred contribution methods
ea0f2bf Revert "Merge branch 'vcsrepo'"
a5716e4 Revert "Merge branch 'vcsrepo'"
94f0b93 (#8704) Give better errors for invalid fileserver.conf
38801dd (Maint.) Disable cleaning of storeconfigs.
023d959 (#8690) Accept 'global' options in Puppet Faces
bff817c (Maint.) Fix spec failures related to leaking state.
ccd622a (#1886) Clean up `node clean` for merge.
c315da0 Fix #1886 - Add node cleanup capability
7e6fc0d Deprecate RestAuthConfig#allowed? in favor of #check_authorization
6401dfe Fix #6026 - security file should support inline comments
0c385f1 Fix #5010 - Allow leading whitespace in auth.conf
8da0486 Fix #5777 - rule interpolation broke auth.conf CIDR rules
1d4acb5 maint: Suggest where to start troubleshooting SSL error message
fb2ffd6 (#8596) Detect resource alias conflicts when titles do not match
778127d maint: Fix cert app to print help and exit if no subcommand
0366b18 (#7293) Set default format for SSL-related faces.
cc2c3ed (Maint.) Unquoting HEREDOCs.
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
10e05ad (#7266) Move Certificate option validation into face.
d522b0b maint: Fix Face testing bug 1.9.2 revealed.
ae36003 (#7290) Update indirected Faces to avoid unknown options.
88e9cd2 maint: don't print inside action implementations.
82e5fa9 (#8561, #7290) Implement the option contract fully.
77441be (#8561) Unify validation and modification of action arguments.
69b4e70 (#7290) Fail on unknown options.
6bec2df (#8561) Use canonical names for options to actions.
532c4f3 (#7184) Load the core of obsolete versions of Faces.
2cd3bc4 (#7184) Find actions bound to other versions of Faces.
1e0655e (#7184) Centralize "find action for face" into Puppet::Face
0396611 maint: better error reporting when test fails
e639868 Confine password disclosure acceptance test to hosts with required libraries
395c174 (#7123) Make `find` the default action...
fd6a653 (#7123) Support runtime setting of 'default' on actions.
b75b1c1 (#6787) Add `default_to` for options.
8820a78 Replace calls to Array#count with #length
bdd6a17 Fix order-dependent test failure in certificate_status/file spec
c830ab0 (#6789) Port SSL::CertificateAuthority::Interface to a Face
cc311ad maint: SSL::Inventory.serial should report missing names.
72abe6c (#7204) Consolidate Semantic Versioning code.
d02000b (#8401) Document that --detailed-exitcodes is a bitmask
a109c90 (maint) Cleanup and strengthen acceptance tests
c4848d2 maint: Fix documentation link for fileserver configuration
b268fb3 (#7144) Update Settings#writesub to convert mode to Fixnum
b82f29c (#7699) Help command should only list options once
4a2f22c (maint) Fix platform dection for RHEL
45b3908 (#4142) Fix module check not to fail when empty metadata.json
1feccc3 Revert "Merge branch 'ticket/2.7.x/7699_fix_help_listing_options_twice' into 2.7.x"
ae3ef42 (#7699) - Help should only show options once
5826f73 (#8032) Add containment to create_resources
98cd89b (#8147) Update test for default reporturl
f6882d6 (#8147) Change default reporturl to match newer Dashboard versions
111a4b5 (#6857) Password disclosure when changing a user's password
Fix cross branch confusion on 2.7.2rc2
8ec0804 (#8301) Red Hat spec file for 2.7.2rc1 won't work
2263be6 (#5108) Update service type docs for new hasstatus default
902c414 Update configurer_spec.rb to work with Ruby 1.8.5
7ad1b04 Clean up indentation, whitespace, and commented out code
014d952 Remove order dependency from functions integration spec
243aaa9 (#7956) Porting cron tests
3e3fc69 (#7956) Port resource acceptance tests
534ccfe (#8048) Gem install puppet no longer fails if rdoc enabled.
bbde5b5 Readying for release of 2.6.9
5160822 Clean up indentation, whitespace, and commented out code
92a8f4a Remove order dependency from functions integration spec
31554c0 (#6854) Update Red Hat spec file
cba645c Bumping release in lib/puppet.rb and updating CHANGELOG.
43027de Bumping RPM spec file to 2.6.9rc1.
99330fa (#7224) Reword 'hostname was not match' error message
1d867b0 (#7224) Add a helper to Puppet::SSL::Certificate to retrieve alternate names
db1a392 (#7506) Organize READMEs; specify supported Ruby versions in README.md
de06469 (#5641) Help text: document that puppet doc takes modulepath, manifestdir, and environment options
381fa40 (#6418) Make test 64118 more portable
98ba407 (#7127) Stop puppet if a prerun command fails
6996e0b Do not needlessly create multiple reports when creating a transaction
caca469 (#4416) Ensure types are providified after reloading
413b136 (#4416) Always remove old provider before recreating it
d866ce1 Cleanup indentation, comment, and unused code
d1c965a Make temporary auth.conf in acceptance test readable by Puppet
4af9784 (#7117) Use a different auth.conf instead of overwriting the default
ecde134 (#3360) Delete SSL directory in acceptance test before running
b502423 Update acceptance tests to use with_master_running_on
053e613 Remove pending copy of an active acceptance test
98f58ce (#2128) Add WARNING for node_name_{fact,value} descriptions
1cd848c (#2128) Whitespace only reflow commit
d9b5c1a (#2128) In-line docs for node_name_{fact,value}
3f0dbb5 (#650) Allow symlinks for configuration directories
c260cf1 Fix acceptance tests not managing their masters
1c70f0c (#2128) Add support for setting node name based on a fact
c629958 (#2128) Get facts before retrieving catalog
cd4fe14 (#2128) Add the ability to specify a node name
8ebec1e (#7193) Fix path issues with acceptance tests that call old shell tests
16b2311 (#6885) puppet agent fingerprint requires --verbose to return a value.
77a5987 maint: Confine augeas specs to require the augeas feature
8eb0e16 (#2728) Add diff output for changes made by Augeas provider
a00fd25 maint: Refactor specs in preparation for making node name more flexible
2f8bc26 maint: Fix order dependent test failure
c02126d (#5966) Add support for hostname regular expressions in auth.conf
75e2764 (#5318) Always notice changes to manifests when compiling.
bc71266 maint: Fix order dependent spec failure for face indirection
6547835 (#7690) Don't blow up when listing terminuses available for faces
0bcbca5 maint: Dedup the loadpath so we don't have to walk it multiple times
4a5e99d (#7681) Add an acceptance test for resource refs with array variables
996dc07 Maint: Fix ellipses for short descriptions
53af6f3 (#7563) DRY: Remove indirector boilerplate from individual faces
74aff59 (#7564) Finish templates
3026333 (#7561) Complete help text for all faces and actions
13e473e Maint: Add ellipsis to generated short_descriptions.
89d447b (#6962) Add "arguments" method to help API
646919e (4123) Fix test for 4123/4 on old egrep in cent4
b101804 add puppet master polling step for ticket 7117
9145569 maint: Remove reliance on system clock from schedule spec tests
107b38a maint: Fix pacman provider to work with Ruby 1.9
8eea3f5 Added the vcsrepo type and providers to the core
8f0cecf Added the vcsrepo type and providers to the core
4645c99 add puppet master polling step for ticket 7117
17e7223 (#7507) Add exclude filter for ruby 1.9 spec failures
181098b (#7502) Fixed parser spec for ruby 1.8.5
9c3bedd (#7507) Add more 1.9 filters
f037662 (#6395) Add extpuppet help, eval, and interfaces
4d4d587 Adding a sleep state post starting master
c81f5c6 Adding a sleep state post starting master
d1cc24f maint: fix spec_helper inclusions again.
3ac7aed (#7523) Refactor the grammar to reduce duplication
d22b130 (#7114) Fix specs for ssh authorized key parsed provider
551cb3e (#7114) Target returns correct value
15c6fc7 (#7114) Add integration tests for authorized_key
a5ac82a (#7114) Improve unit tests for ssh_authorized_key
1c7f0c3 (#7114) Improve value validation for authorized_key
0b8ebac (#7300) Fix instances method of mount provider
1dc662a (#1853) Pacman package provider
6bb2a85 (#1853) Pacman package provider
c8775f9 (#7259) Remove ActiveRecord requirement from indirector face spec
1ad8158 (#7259) Do not try to load all Terminus classes when configuring the Indirector
8b76be3 (#3836) External nodes should only capture stdout
d63fc34 Revert "(#7220) Add the ability to "inherit" options."
c21539f maint: sync 'authconfig' to 'rest_authconfig' setting
81d566f Fixed #7481 - Added MIT license to Thomas Bellman's function code
1695dac (#7264) Docs: Clarify that subscribe/notify imply require/before
8f907f2 adding test for ticket 7139
90eb937 (#7139) Accept '/' as a valid path in filesets
1f3b8e7 (#7300) Add specs for the mount provider
1b2a7d9 case seems needless here as there is only two opts, also the rest of the file seems to use if so this should make things more consistant
729336e (#6845) Mount writes incorrect vfstab entries
16cf1ac (#6442) Be able to start agents --listen without namespaceauth.conf
e059539 Update CHANGELOG for 2.6.8
ac0581f (#7101) Fix template error messages in Ruby 1.8.5
9d2500e (#7101) Fix template error messages in Ruby 1.8.5
0352402 (#3420) Nagios "name" attribute does not output correctly
f656818 (#4487) When setting environment on a host, ensure it is a string.
89e9a21 add test for ticket 7101
74498af add test for ticket 7101
2cce326 add test for ticket 7101
c1edcb2 add test for ticket 7101
9329a1f (#7220) Add the ability to "inherit" options.
c306db2 (#6487) Add some testing for OS X version support in DirectoryService provider
0008b63 (#6487) Directoryservice provider will fail in future OS releases
f21162b (#6368) Make the File type autorequire its nearest ancestor directory
c3a76a9 (#7021) Fix order dependent spec failures
7bd6a2f maint: Remove unused code
34f9f41 Maint: Fix a #4655 introduced log inconsistency
6981ee5 Maint: Fix a #4655 introduced log inconsistency
cb43cfc Moving tests from Puppet-acceptance repo
ac428b9 Move tests from Puppet-acceptance repo
db26326 Move tests from puppet-acceptance repo
6b18f8f Move acceptance tests from puppet-acceptance repo
9a5bf6e Fixed #7166 - Replaced deprecated stomp "send" method with "publish"
a18ac78 maint: Fix PSON order dependency in test
656eff8 (#4655) Allow stage to be set using a default class parameter
b3ab0d9 (#4655) Allow stage to be set using a default class parameter
7d3c303 Fixed #7166 - Replaced deprecated stomp "send" method with "publish"
7f658e6 vim: Initial ftplugin and indent support
ccbe9f3 Fixed #6681 - Remove --force-yes option from aptitude is used
2.7.1
===
a49d5b8 (#8048) Gem install puppet no longer fails if rdoc enabled.
2.7.0
===
1a33bf8 (#7506) Specify supported Ruby versions in README.md
d4c499d Updated CHANGELOG for 2.7.0rc4
dbe2310 Maint: Update static man pages for 2.7.0
50d188c Maint: Update static man page generator for Faces.
f370d5a (#7833) Several help text/template edits
90d2cf0 maint: more work on regexp matching in Test::Unit assertions.
8c71df2 maint: acceptance tests need to search for bin/false
0ae4732 (#7828) Fix whitespace in synopsis generator.
b4e9791 maint: handle incoherent Test::Unit assertions.
48aafa3 (#6873) Add Static Compiler terminus to 2.7.0
9017fea (#7728) Acceptance test for whit notifications.
973e752 (#7728) Suppress notifications from container whits.
1772363 (#7764, 7775, 7778) Revisions to Faces help text
5a9998e (#7773, 7776, 7764) Several help template tweaks
5587b94 maint: remove an unhelpful pending test.
bbf0a02 maint: fix misnamed acceptance test for #7139
d4e6c26 (#7624) Manually fetch all properties in instances.
c8df027 (#7193) Fix path issues with acceptance tests that call old shell tests
31bf55c (#7632) Make secret_agent application compatible with secret_agent face
c5448b7 (#7624) Auditing should not be enabled by default for purged resources.
b70f32a (#7746) Fix bootstrap issues from #7717 fix.
be233c3 (#7683) Use ronn, when available, to render the output.
2389bdf (#7683) Add a 'man' face and subcommand to Puppet.
e647f70 maint: remove obsolete work-around code from help face.
796900b (#7699) Don't duplicate inherited action names on faces.
a23cfd8 (#7177) Deprecate implicit 'puppet apply' for 2.7.0
3f47b0c (#7717) Layout cleanup for subcommand extraction.
8072b4b #7211: Test unknown options don't shadow unknown actions.
dd8108c #7211: nasty logic error with global Face options taking arguments.
618495c #7211: more helpful error messages in various cases.
7df1fa4 (#7708) Delete extended documentation from configuration reference
2935feb (#7707) Document signals in puppet agent and puppet master help
3facc33 add puppet master polling step for ticket 7117
68c106e (#5318) Always notice changes to manifests when compiling.
a5a78a5 (#7557) Remove Faces Application
ea7908b maint: Fix order dependent spec failure for face indirection
2aa9f2f (#7690) Don't blow up when listing terminuses available for faces
9447cb9 maint: Dedup the loadpath so we don't have to walk it multiple times
149a12f Maint: Fix ellipses for short descriptions
7688706 (#7563) DRY: Remove indirector boilerplate from individual faces
4662f4d (#7564) Finish templates
331d812 (#7561) Complete help text for all faces and actions
069a6b8 Maint: Add ellipsis to generated short_descriptions.
ebc642b (#6962) Add "arguments" method to help API
163ff6b (#7681) Add an acceptance test for resource refs with array variables
9f6dec2 (#7681) Allow array variables as resource references
76ad2bb (#7507) Add exclude filter for ruby 1.9 spec failures
3682025 maint: move trap call to Signal so we can stub it for specs
fc0add1 Updated CHANGELOG for 2.7.0rc3
83c7563 (#7259) Remove ActiveRecord requirement from indirector face spec
aad2fd7 (#7259) Do not try to load all Terminus classes when configuring the Indirector
3378841 Adding a sleep state post starting master
d972cea (#7507) Add more filters for Ruby 1.9 spec failures
9da1454 (#7507) Add ability to filter Ruby 1.9 spec failures
47e4ac9 (#7507) Fix when_invoked action specs in Ruby 1.9
809b6fe (#7297) Fix Puppet::Resource#to_manifest in Ruby 1.9
3197e21 (#7298) require 'English' to provide $CHILD_STATUS in Ruby 1.9
48923af (#7291) Fix issues with instance_methods in Ruby 1.9
68065ff (#7291) Fixed ascii problem with Ruby 1.9.2
1abb7c0 (#7291) Fix Ruby 1.9 face failures
6159466 (#7291) The 'script' version of actions needs options argument
09f5d9c (#7469) Add license to test face so tests pass
a44cbb1 (#7264) Docs: Clarify that subscribe/notify imply require/before
9377507 (#7468) Stub spec that tries to connect to pypi.python.org
5db214c Prevent spec failure caused by network device mock leak
3722520 Fix #7299 - do not require net/ssh for running rake spec
b983386 Updated CHANGELOG for 2.7.0rc2
61edff9 (#7353) Remove :for_humans format entirely.
d2b5ec6 Adding test for ticket 7139
6f2a129 add clean-up step to test for ticket_5477 to prevent site.pp from leaking to other tests
92905ff fixed test for ticket_7117
5076c37 (#7179) Modify default ACL for /node/<name>.
7b71745 (Maint) Adjust documentation whitespace
358418c (#7303) Remove reference to not-yet-extant man action
dce072a (#6962) Add self-documentation data to puppet faces
855a0ec Maint: adjust faces.rb's help to match that of other applications
75f164a (#7304) Remove full puppet help output when subcommand cannot be found
8a8e198 adding test for ticket 7117
dda3264 (#7353) Note the :for_humans compatibility issue.
efd1181 (#7353) Use :console rendering format in our own code.
5986e8a (#7353) Unify rendering in the face_bace application.
a4e735e (#7353) Add 'console' format to FormatHandler
94f0b09 add base test for ticket 7117
dc0088f (#7277)Fixing all secret-agent functions, and the agent itself
1f112cd (#7139) Accept '/' as a valid path in filesets
18b3584 (#7329) Consistent naming for rendering formats and hooks.
8f81f56 (#7326) Fix faces on Ruby 1.8.5
5569fad (#7117) Return the environment as a Puppet::Node::Environment in uri2indirection
5120a95 (#7276) Better reporting from the plugin download action.
bb889bf (#7276) Create a plugin face application.
5490f7a (#6962) Added 'returns' block to action documentation.
0d6ac04 maint: remove emacs 'coding' cookie from files.
48903f5 (#7278) Improve utility of the Catalog select action
45adc1a (#7279) Adding some basic file actions
a4a274b (#7315) Fix `to_pson` method to render correctly.
1b42725 (#7314) Faces fail horribly when one has a syntax error.
86c6ec2 maint: move the indirector face base out of puppet/face
c63e9c2 maint: reset more global state in testing faces...
b20e977 (#7304) Improve help from `puppet foo`
3bb8bd3 (#7317) better error handling in CLI face facade.
b23cc8a (#7282) action without `when_invoked` should fail...
040e0fd (Maint.) Fix accidental debug output in tests.
65b9a3c (#7221) Strip bad whitespace from face and action docs.
97ae812 (#7248) Fail if two aliases of one option are passed...
207deae (#7289) Specify order for option decorations.
1707f27 Revert "maint: better error reporting for argument count mismatch."
cd474b0 maint: better error reporting for argument count mismatch.
69e4b1c (#7122) Enforce call arity on actions in the CLI wrapper.
351b6fc maint: add a 'print' matcher to rspec, to inspect std{out,err}
be4d7e6 (#7269) Fix error reporting for bad render formats...
632a0a0 (#7269) Better error reporting for bad render formats.
80adaea (#7160) Support 'json' as a rendering method for CLI faces.
0256d67 (#6962) Add integration tests on Face documentation.
e8eb290 (#6962) Finish documentation API on Face options.
6e152ad (#6962) Give copyright and license for all faces.
b8525c9 (#6962) Fill out documentation on Faces and Actions
59e7ef1 (#6962) Move documentation support into a module.
092ab09 (#6962) Extend documentation API for Faces.
c627fad (#7251) Let exceptions raised in decorators rise.
bbf777f (#7249) Publicize ActionBuilder DSL methods.
95ed9aa add test for ticket 7101
6064e8e (#7101) Fix template error messages in Ruby 1.8.5
49c5152 (#7137) Get rid of spurious info messages in useradd
349bd96 Fix test ticket_6928_puppet_master_parse_fails
f25acf9 maint: add the 'to', 'not_to', and 'to_not' aliases to rspec...
f77304b (#7157) Return a non-zero exit code on face failure.
435c826 maint: use the exit_with helper everywhere...
96195c1 maint: add an "exit was called" matcher for rspec.
822d530 maint: clean up test headers on face spec files.
5c24541 Fix #7084 Make the log messages produced by whits less confusing
c7a0270 (#7121) Download plugins and upload reports in secret agent!
2a2226c Revert "Fixing Facts pson methods more resilient"
7591de7 maint: fix a race in catalog compilation versioning.
aaf7e23 Revert "(7080) Adding json support to Indirector Request"
17d176b Revert "Adding json support to Puppet::Node"
27e0831 (#7181) Rename configurer face to secret_agent.
de2199f (#6928) Don't blow up when the method is undefined...
a0de328 (#6928) backport Symbol#to_proc for Ruby < 1.8.7
f17f6bb (#7183) Implement "invisible glob" version matching for faces
7414ee7 maint: better disabling of Signal#trap in our tests.
03bd559 maint: more robust listing of valid faces.
7db4793 maint: clean up testing code a fraction...
eeb8236 maint: better error report for a missing version of a face.
677752d maint: handle face clear/reset sanely in the interface spec.
7b3744c maint: stop stubbing log level setting.
220f308 Move tests from Puppet-acceptance repo
379b46d (#7116) Handle application-level options in parse_options
a1db585 maint: fix gratuitous whitespace in the code.
601baf1 maint: remove redundant context from the test.
5d7ef5c (#7062) better argument handling in the action wrapper methods
33b5580 maint: move method comments outside the comment.
c87d6c9 Fixed #7166 - Replaced deprecated stomp "send" method with "publish"
557767b maint: Remove unused faces code
311e3ec maint: mangle grammer in rspec to avoid Jenkins fail...
0fed94f (#7013) Wire up rendering hooks on the CLI.
12098f2 (#7013) Handle rendering modes out in the application layer.
5938452 (#7013) Strip out old face-wide rendering defaults.
5258e06 (#7013) Return bound methods for when_rendering hooks.
86801b5 (#7013) Support 'when_rendering' and 'render_as' in actions.
be23b84 (#7013) better default rendering support for faces
e6caa24 maint: make sure we don't ever default to being default...
36b100a maint: print 'false' in the default render method.
2cf692c maint: delete README.strings, which is out of date.
22355dc maint: test the 'help' face has the default action 'help'
4efba71 maint: drop multi-version support from action loading.
266f937 (#6962) Add 'description' to faces and action.
32c667c (#7132) Reject 'summary' text with newlines embedded.
1251311 (#7108) Update help/man text for puppet kick
eeb1b60 (#7108) Modernize description of --listen in defaults.rb
3ec9526 Maint: puppetmaster -> puppet master in defaults.rb
5a10093 (Maint) Fix a leaking spec, patching intermittent failures.
07b677c Merge remote-tracking branch 'community/feature/puppet-device' into 2.7.x
13e64fe (#7131) Remove support for optional arguments to options
977684e (Maint) Fixing an order-dependent failure.
9d2ec21 (#7013) Add support for required options.
eeb82f8 (Maint) Code cleanup.
d85c2a8 maint: Fix the missed failure from the previous commit
e946a17 maint: Fix a broken Puppet::Node::Facts spec
d80500f maint: speed up testing output of the help face.
9264526 (#7115) Enable default actions.
ab541fa (#7059) Use option hooks for the indirector terminus option.
f770325 (#6978) Enforce the calling convention of option hooks.
c00e03d (#7059) Set the CA location using option hooks.
dca1f07 (#6978) Add before and after decorators to actions from options.
0c60aa2 maint: delete an empty describe block containing no tests.
e424740 Adding json-specific matchers
f37b2e1 Making watchr resilient to syntax errors in tests
d3c94e6 Adding json support to Puppet::Node
155b16d Fixing a failing test resulting from a fixed bug
e0615cb (7080) Adding json support to Indirector Request
07a7a68 Fixing Facts pson methods more resilient
ff08ba2 (7118) Adding summaries for all faces
a509821 Cleanup trailing whitespace
5528911 (#7111) Clarify scoping deprecation warning
ca9d68f (#6408) Update puppet cert help for new subcommand action syntax.
174e87a (#4258) Fix pkgutil spec test to have the correct provider
e119739 (#6928) Add a notice to Parser#validate action when using default
9bc4bce (#7103) Fix HEAD requests in the HTTP handler
97e9e5f Updated CHANGELOG & version for 2.7.0rc1
5915814 Revert "(#6928) Removed --ignoreimport"
24a277c (#6928) Removed --ignoreimport
fc36e8d (#6928) Remove --parseonly
a688461 (#6928) Add a Parser face with Validate action
4ef622e (#6830) Fix sha1 to digest/sha1 require issue for Ruby 1.9
64c12bd (#6830) Fix UTF-8 encoding issue for Ruby 1.9
2d459fc (#6830) Fix string method sub call on a symbol for Ruby 1.9
78e181e (#7059) handle inherited action binding scope
cc0f414 maint: ensure we handle '-foo=' options correctly in faces.
f78ab09 (#2150) Fix File const lookup when configuring routes
cb552af (#4258) Remove superfluous command check that called pkgutil
fd98341 (#4258) Fix fd leak opening pkgutil config files
7726dc3 (#4258) Permit variations of -nv in both pkgutil.conf files
f8c2f1a (#4258) Stop file and config checks from breaking spec
ef86105 (#4258) Check wgetopts in pkgutil.conf
e852580 maint: install erb templates under lib/
db11770 maint: clean up the spec test headers in bulk.
4dd6a77 (#7056) Use 'face' rather than 'faces' in the production code.
941c56a maint: eliminate deprecated since 2008 code from Puppet.
4672141 (#6117) Add POST support to indirector requests
7b4d936 (#6962) Move option handling into #parse_options, not #preinit.
7899462 maint: whitespace cleanup for puppet/util/command_line.
826d5df (#6962) delegate global usage to the help face.
9496067 maint: avoid making temporary dirs during testing.
fe6d595 (#6962) Integrate legacy subcommands into the help face.
acbbd52 (#6962) Clean up testing further.
648e3c0 (#6962) Better argument checking for help.
217c156 (#6962) Report the template filename for help render errors.
ec988e2 (#6962) Move the logic for help layout into erb templates.
2a87f41 (#6962) Override 'render' in help to just return the string.
6570827 (#6962) Add summary help for actions on an individual face.
cdc5fec (#6962) Implement 'summary' for actions.
91c29a7 (#6962) Extract summary from legacy applications for help.
d13a938 (#6962) Initial support for legacy applications in help.
26db645 (#6962) render prints the rval; fix help subcommand.
3602102 (#6770) Don't pollute valid face list when #face? is called.
14b1e00 (#6992) Expose available_subcommands as a class method.
4eccd53 (#6962) Implement Face#summary support for the help face.
1b4d7a5 (#6962) Create the basic shape of the help face.
d8dfb1f (#6962) Implement 'summary' for faces.
dc2675d (#6770) Improve test robustness against 'require'
7228f58 maint: finish transition of application help to return strings.
a20810e maint: direct people to the expected spec file...
8b13e2b maint: watchr should respect personal account-wide defaults.
6fcf03c maint: added testing for Puppet::Faces#[]
20d9ac1 maint: fix indentation in the watchr script.
0c6f50c (#775) Don't require command when removing cron entries
b2831e1 (#2150) Add routes file for indirector
e569f3b (#5027) Use Puppet#warning for deprecation_wanring instead of Kernel#warn
f6fb193 (#5027) Spell deprecation correctly
d0a5652 Fix for #5027 -- generate a deprication warning for dynamic lookup
739260b Towards 5027 -- add options hash to lookupvar as with setvar
d7201ed Refactor for 5027 -- get rid of lookup_qualified_var
10230cf Step towards #5027 -- scopes should know if they are dynamic
e5609ff Step towards #5027 -- add Logging#deprication_warning facility
1954bbf Refactor on the road to #5027 -- remove unused Scope#strinterp
31f8e66 Refactor en route to #5027 -- remove usestring parameter from lookupvar
d5dc303 Fix for #5063 -- explicitly scope internal variable lookups
b3baee8 Refactor on the way to #5063 -- removing unused Scope#level
dd33eac Refactor prior to #5063 -- remove dead "topscope?" code
cb01221 (#3360) Add an allow_duplicate_certs option
d2145d9 Fixed #5684 - Move to Apache 2.0 license
5075658 Fixing Indirector::Facts::Couch loading
26b6b37 Fixing dependency loading in Rails::FactName
379a379 Fixing 'puppet faces' application
69db817 Fixing the watchr script
8ec9d13 Fixing FaceCollection#faces
7e9707a maint: Fix sporadic sqlite error
64be97b maint: Fix sqlite3 require to really be optional
6ed0051 maint: just require 'spec_helper', thanks rspec2
f9271b9 maint: delete dead darwinport package provider
a19fbb4 maint: don't take over signal handling in tests...
f9a2ffd maint: use FileUtil to remove files, not exec
78cb48c maint: disable garbage collector during individual test cases.
d43f850 maint: Ruby < 1.8.7 knows size but not count
101c6ed maint: Get tests passing on Ruby < 1.8.7
9490cc9 (#7026) Remove whits from reports when finalizing
3094d42 maint: Add Array combinations method
e0a2e91 maint: mark tests pending for a discovered bug...
49dcc24 Updated confine in Spec test for RSpec 2
28e3db8 Add management of router/switchs global vlans
1cb1841 Cisco Switch/Router Interface management
596571f Base class for network device based providers
6560da5 Ssh transport for network device management
358245a Telnet transport to connect to remote network device
c947a6d Remote Network Device transport system
aa34b72 Introduce a module for some IP computations
79f4774 maint: mocking 'require' causes random stack-overflow failures.
d9f23c0 (#6969) String failures differentiate between invalid string/version
292a8b9 (#6985) Allows indirectors to accept a hash as an argument.
d04567f (#7005) added require 'tmpdir' to spec helper.
87ed318 (#7012) Split plumbing into Puppet::Interface
8d144d0 (#7012) Update references in code to use face(s)
5592034 (#7012) global rename of strings to faces.
6be1eb8 Maint: fix a load order problem with type(:component)
03afbad (#7006) Add a missing require to puppet/string/option.rb
cab5672 (Maint) Fix uninitialized constant.
27bd1ad (#6983) mark test pending until string is fixed...
a03790d (#6972) Handle ca-location in the certificate string.
7e7d246 (#6972) Recognize puppet global options in pre-parse.
0b97bd0 (#6972) Clean up OptParse name extraction a little.
d4012db (#6995) Fix indexing of :current on string load.
07a79cf maint: add `write_scratch_string` helper for testing...
a1a09b0 maint: whitespace cleanup for spec_helper.
a125536 (#6995) more robust testing of string loading
2a6c6cb (5200) -- replace containers with sentinals
8ddd994 (#6982) Patch the Certificate String against (#5528).
e20e618 (#5528) Add REST API for signing, revoking, retrieving, cleaning certs
0950d09 (#6949) Fix passing positional arguments to actions.
4d2a367 (#6964) use 'when_invoked' rather than 'invoke' for actions.
75ef3af maint: added testing to ensure we inherit options correctly.
0c74495 (#6749) Handle options with inline arguments.
cec3b6e (#6749) Extract the action from the arguments cleanly.
5a0b547 (#6749) Fix optional vs mandatory argument handling.
8b37d70 (#6749) Polish the CLI option pre-parse implementation
37c97cd (#6749) clean up various testing bits...
d328af7 (#6760) set terminus in indirector string base class.
4d23d60 (#6749) add a shim around the action implementation.
eb4c4fb (#6749) Start porting existing strings to the options API.
8723b1c (#6749) code and test cleanup of Application/StringBase.
3d88808 (#6749) base indirector string should fail on invalid terminus.
c52261c (#6749) disable Action#invoke for this release.
1635454 (#6749) Remove "save does not work" language from strings.
423fe1f (#6749) string cli base: implement preinit CLI parsing
512778f (#6749) detect duplicate aliases in a single option statement.
3bb6145 (#6749) fix an inheritance bug in ActionManager
a113e8f (#6749) implementing option handling in CLI string wrapper
5bba1a2 (#6749) Implement support for options on strings and actions.
1400fec MAINT: nicer to_s for actions, for user-focused rendering.
05b434d (#6758) Pass options as an argument to string actions.
a3f5f97 MAINT: fix error reporting when you set terminus incorrectly.
6554fd3 MAINT: delete a test that can't work on 2.6.
56ba0a2 MAINT: implement a pending test for code we wrote...
76760db MAINT: use a table for table-style tests...
0e834af MAINT: fix up tests that depend on the LoadError message to work.
5dc994c (6911) Cleanup and renaming of transaction internals
8af29c8 (6911) Core change -- replace topsort with frontier ordered by salted SHA1
8b5ffde (6911) Add bookkeeping facade around Transaction#relationship_graph
ee1df78 (#6937) Document the recurse parameter of File type.
fa5c2b1 (6911) Cleanup of generate_additional_resources
7b83cd9 (6911) Refactor to localize eval_generate dependency assumptions
f76db9e (maint) Fix for require order issue
127501e (6911) Use normal methods to implement "depthfirst?" test
505a48c (Maint) Bugfix for failing requires inside Puppet Strings.
5a90355 maint: Use bracket notation instead of define in specs
f7f1e58 (#6770) Fix Puppet::String#load_actions.
1ac7f63 (#6830) Fix tests that depended on special inherited behavior
29f3dda (#6830) Fix overly stubbed tests
5e9dfdc (#6830) Fix instance_variables now comes back as symbols
893817f (#6830) Fix badly stubbed Time object in test
ade4efe (#6830) Fix MD5 handling to work with Ruby 1.9
bfac57a (#6830) Fix File class scoping
a520c5e (#6830) Handle case where array is actually a string
85f3b76 (#6830) Fix case where instance_variables returns symbols in Ruby 1.9
4609e20 (#6770) Change versioning; adopt :current over :latest.
b859baa MAINT: the API is officially named "string" as of this moment.
076de13 (#6855) ResourceType#search now accepts a regex
daaa048 (#5477) Allow watch_file to watch non-existent files, especially site.pp
e16a383 Fixing #6851 - ResourceType#find/search loads types
29268f3 Fixing Module#path detection
da082d5 Fixed #6850 - Clean up ResourceType#to_pson
88aeb04 MAINT: fix the misordered invocations in action.
b42c57d (#6830) Fix stat method calls to not use an unneeded argument
6aea116 (#6770) Add support for version :latest.
1af9bb2 (#6770) Add version lookup and comparison.
78371a7 (#6770) Refactor Puppet::Interface#initialize.
53b0656 Config#print action always returns nil
8124f8e (#4576) Raise an error when a node is classified into a non-existent class
633f63c (#6833) support 'script' as a short form of 'action'
b3c059e (Maint.) Require 'puppet/interface' in spec_helper.rb
c25fb94 (#6770) Rename Puppet::Interface::interface method.
7aa8f22 (#6770) Changing versioning to semver.
635751d Propagating an argument to search out of core.
1187a0e (#6770) Add basic versioning for interfaces.
36a5665 (#6820) Fix File class lookup in the file type for Ruby 1.9
8c32db7 (#6820) Fix nagios parser to use proper hash syntax for Ruby 1.9
054eac6 (#6820) Fix Invalid multibyte character
7a4fcf2 (#6820) Fix RDOC parser to work with Ruby 1.9
341654e (#6820) Fix invalid next that should be a return
3d43d86 (#2782) Fix constant_defined?
961c716 Added list action.
a7a9e12 Alter generate action to work on CSRs only.
a1ce253 Adding Certficate#generate
562ae5f WIP - all tests fail
562bd0f Use the new name for the terminus.
5d7715b Factoring cert status app back into certificate.
af79d3c maint: Fix order-dependent spec failures
847ac20 maint: Implement an InterfaceCollection class to manage interfaces
6180397 (#6527) Fix pip tests
557ed85 (#4258) Fix hash duplication affecting canonical provider instance
0170ceb (#6527) Fix uninstall problem and refactor
af42367 (#6527) Added pip package provider.
ee66f36 (#6814) Add missing require for specs
50ba62d maint: Make args to Catalog.select explicit
e3d2486 (#6814) Create a dedicated Action class
a58bf95 (#6786) Change interface storage and access.
f6da333 maint: Change code for finding spec_helper to work with Ruby 1.9
307df20 Fix error "invalid multibyte char (US-ASCII)" under Ruby 1.9
4156edc (#6566) Replace tabs with spaces
d448763 (#6566) Fix ruby 1.9 incompatible case statement
517fd2f Fixed #6566 Replace ftools with filetuils in rake gem task
ad8cc54 (#6555) Fix another ruby 1.9 incompatible case statement
0844a17 Fixed #6555 - Fixed two more when then colon issues
923d613 Fixed #6555 - Ruby 1.9.x returning Invalid next (SyntaxError)
66a4f36 Fixed #6555 - Ruby 1.9.x warning: class variable access from toplevel
c2627a3 (Maint.) Remove Puppet::Interface#unload_interface
63f33d0 (#6805) Add a "configurer" application
84ba21e Fixing a load-order issue in Puppet::Interface
072becf (#6806) Improve error checking and reporting for interface naming.
ba67cc8 (#6785) Internal consistency for `--terminus`.
a7173dc (#6786) Fixing a number of failing tests.
9c85d70 (#6785) Rename the --from option to --terminus.
b187e07 (#6786) Removing the #interface method.
7c99dd9 (#4258) Use pkgutil -a to reliably determine package common names/aliases
ab5bc35 (#4258) Update pkgutil spec for recent impl changes
cf873c6 maint: Silence test output in the spec run
f4401d3 (#6722) load all functions before testing...
4905956 (5909) Function to dyncamically generate resources.
1a55c7a (#5479) Test that we auto-require the zone dataset.
0a2a58c (#5479) Autorequire zfs filesystem when zone dataset is configured
e582709 (#4258) pkgutil: bug fix: if shortname is not equal to package name
682686f (#6441) Add mount fixture for AIX's /etc/filesystems
349f6f2 (#6641) Make it easier to add future platforms to the suite.
6a96584 (#6441) Mark solaris tests pending, because we can't stub it.
b4f1b98 (#6641) fix mount provider tests broken in the 2.6 merge.
3b89f32 maint: use chdir rather than depend on bash for win32
2a91572 (#4798) Make rdoc work if moduledir & manifestdir overlap
28ce355 maint: Fix rdoc when documenting manifest files
58ac7d3 (#4258) pkgutil provider: better handling of short package names
9a1c3b5 maint: spec/integration/configurer has races in time checking.
75af582 maint: Move puppetdoc settings to defaults so we can use them in tests
124ff3c maint: Fix a randomization test failure
455d197 (#6582) Don't demand the checkout be named 'puppet'.
85a743b (#6582) stub puts to prevent screen output when testing help.
ec23d96 (#6582) eliminate a backtrace from mismatched block arguments.
93082e4 (#6582) unstub Puppet settings to improve indirector queue tests.
92499c8 (#6582) Eliminate the last vestige of the unit tests from the specs.
3954576 (#6582) eliminate fakeresource use in ssh_authorized_key spec.
53b6df3 (#6582) eliminate fakeparsefile helper method.
0f6faf5 (#6582) Eliminate the old fakedata helper method.
f490526 (#6582) move more helper code into methods, out of RSpec#configure
6b8f1b7 (#6582) add fixture helper methods to replace unit test code.
7c9f1b8 (#6582) order RSpec global :before and :after hooks naturally.
b311651 (#6407) Fix spec test hang with Mocha >= 0.9.11 in zlib testing
af2c85b (#6551) remove deprecated 'env' parameter to the 'exec' type
f67e7fa Modifying Facts.upload a bit
ece0c8e Fixing #16 - nodes default to yaml
63263a4 Fixing #13 - showconfig moved to indirector
23064bb Adding a test for fix to #14
353b914 (14) updated interface_base to support multiple command line arguments
9c0e55b (#5496) Added tests for the new zpool output format
b1d9728 (#5496) zpool provider supports new 'zpool status' format
026eba3 Revert #5691 "Merge remote branch 'brice/feature/process-instrumentation' into next"
905ff3a Pretty-printing json using "jj"
f0d7684 (#6494) Add setm command to Augeas provider
0026e43 (#6494) Add mv command to Augeas provider
67ed160 (#6494) Add defnode command to Augeas provider
45cba13 (#6494) Add defvar command to Augeas provider
66c994a Attempting to skip loading of duplicate actions
21b541d Fixing plugin usage
59a6485 Adding Application options to Interfaces
4fa54d0 Adding render and exit_code override support
bec807e Fixing 'puppet interface list'
368210e Adding a simple "config" app
c2715c0 Splitting the Application base class
7da0a26 Adding a string form to interfaces
04fb6de Switching Interfaces to be instances
0cbdbce Renaming 'data_baseclass' to 'interface_base'
ef289e5 Fixing indentation
cf79349 Updating readme to reflect requirements
15a53f0 (#4258) pkgutil provider: misc enhancements
cde1baa Fixing Interface listing
eff4eec (#3) Base application should catch SYSINT
a54ee1e (#2) Should not assume interfaces have indirectors
15e225b Add spec tests for pkgutil package provider
8462acd * Fix exception on parse failure of pkgutil output * Fix exception when querying latest version for unknown package
7639d5f Fix non-existent method called in SMF manifest import exception message, updated spec
f5e21f0 (#6324) Use real service resource object instead of a stub
ef9e929 (#6324) Add spec for SMF service provider
b18f045 (#1204) Make rake gen_manpages fail explicitly if ronn isn't present
ae4112b (#1204) Add manpages for modern apps and update puppet.conf manpage
f6485d6 (#1204) Fix --param flag in puppet resource manpage
dac032d (#1204) Make rake gen_manpages output puppet-{application} manpages
a0cff49 (#1204) Update all the manpages
c619520 (#1204) Move man generation task from install.rb to a rake task
9e19d22 (#1204) Edit content and formatting of puppet resource help
f4c7e48 (#1204) Edit content and formatting of puppet queue help
bd14ff5 (#1204) Fix --compile and --apply options
768d9a1 (#1204) Reformat help text for puppet master
3f1c26f (#1204) Reformat help text for puppet kick and inspect
d198db2 (#1204) Reformat help text for puppet filebucket
c35aa60 (#1204) Fix garbled help for puppet filebucket
1800d00 (#1204) Edit content of puppet describe help
f653b8d (#1204) Reformat help text for puppet cert and describe
969b8b0 (#1204) Edit content and formatting of puppet apply help
489b065 (#1204) Reformat help text for puppet doc and puppet agent.
7e3a023 Only printing output if there is any
b3f903a Enabling arbitrary interface names
782ca8d Fixing an error message
0b18cb6 (#6324) Always fall back to svcadm enable except for the maintenance state
9e124e1 Fixing rendering to support arrays
3ffb9ab Moving 'format' support to the application
7a325fe (#6144) add missing zfs properties
9cb594f Finishing the s/data/interface/ in the application
5190aba Adding to README
264a43c Renaming "data" app to "interface"
efca35c Finishing migration from puppet repo
adc9244 Feature #2597 -- generate a DOT graph of cycles on request.
2cf4528 Feature #2597 -- eliminate OpenStruct for performance...
9584cda Feature #2597 -- use O(1) methods as often as possible.
d302628 Feature #2597 -- improve names and whitespace in the code.
9ea74cc Feature #2597 -- report all paths in each cycle found.
e30fd8f Feature #2597 -- remove obsolete licensing comment...
f547118 Feature #2597 -- use iterative DFS in Tarjan clustering.
34a57b8 Feature #2597 -- really find and report cycles.
403adb8 Feature #2597 -- nicer reporting of relationships.
1ad6470 Feature #2597 -- fix cycle relationship notification format.
3f2f1c2 Maint: move puppet resource --help
82e004f Maint: move puppet kick --help
95fc38c Maint: move puppet queue --help
a041e19 Maint: move puppet doc --help
7568b78 Maint: move puppet cert --help
9fdd66b Maint: move puppet apply --help
c61d6d0 Maint: move puppet describe --help
ae78264 Maint: move puppet filebucket --help
fc66e57 Maint: move puppet master --help
9b521d7 Maint: move puppet agent --help
8d569b3 Maint: remove puts and exit from inspect --help
e1191f3 Maint: remove rdoc/usage dependency
025768f Adding license and readme file
809aebe Moving data executables to their own module
fb339cb (#5432) Use AIX native commands to manage users and groups
aa8c09f (#5432) Use AIX native commands to manage users and groups
d65e094 (#5432) Use AIX native commands to manage users and groups
27abd84 maint: Stop stubbing 'use' on any_instance of Puppet::Util::Settings
7ed5251 maint: Work-around for a Mocha bug
52f8ddd (#5432) Use AIX native commands to manage users and groups
9032898 (#5432) Use AIX native commands to manage users and groups
e27d208 Some high-level process name probes
aed4b5f Process name instrumentation infrastructure
b94c1b4 (#5427) Using Propery::OrderedList for host_alias
cca3436 (#5427) Remove redundant testunit tests
c88afa0 (#5393) Add "dataset" parameter to the zone provider
626d756 maint: Use expand_path when requiring spec_helper or puppettest
b9f3847 maint: Fix more order dependent test failures
b67f4c6 maint: Restore a default value that can cause order dependent test failures
094a5c8 (#5211) Added patch and tests for checking the size of the arrary which is returned
0ab5e0f (#2495) Better value validation for sshkey
0747b58 Maint: Modified uses of indirector.save to call the indirection directly.
f77764d Maint: Modified tests of indirector.save to call the indirection directly.
7de6af8 Maint: Add a default value for key in Facts::NodeExpirer#save
beb85d6 Maint: Moved auto-signing logic into an indirector extension
3063000 Maint: Swap the order of arguments to Indirection#save
8766efe Maint: Make http handler code call the indirector through ".indirection"
71ecad9 Maint: Refactor code to use <class>.indirection.<method>
14f8160 Maint: Refactor tests to use <class>.indirection.<method>
3eace85 Fixing indentation
f8e9155 Removing blastwave references and unused PAGER
485ac38 Changing indentation to 2-spaces as per 2.6+ style
9d63171 Single package queries made more robust when dealing with pkgutil noise
f50fac7 Fixing wget verbose regex
0f00bf4 Maint: Removed unused monkey patch that connected OpenSSL::PKey::RSA to indirector
c5a1ca0 (#5391) Include additional zfs properties
3a815e1 (#5375) Rework puppet apply to use configurer.run
99f4d2f Maint: made upstart tests more robust.
9ccd29f (#2866) yum should support downgrade.
04389f5 (#4711) Provide unit tests for yum package provider.
0956757 Fix #5261 Don't escape Unicode characters in PSON
4a2bbbc maint: Fix tests that don't run on their own
f3cd668 maint: Fix a test that was missing a require
7c16215 maint: Fix a test that was missing a require
32dcb31 (#5370) Made metrics and --summarize work with Puppet apply
e825485 Maint: Added assertion to make sure Log.close_all succeeds
cf18353 Maint: Switched spec tests to use a class rather than Array as the log destination.
ee56cfd Maint: Improved spec tests
b089392 Maint: Modified "rake spec" so that it prints full backtraces.
6e51d11 (#5274) Fixed some "rake unit" tests that were inadvertently broken by commit:ee7d2f92f9d3ec45b5c3a9cd3fe2f5832b17f23b
cd8126f maint: Fix intermittent parser spec failures
2052f36 (#5274) New tests for new hosttype/parsedprovider
ee7d2f9 (#5274) New comment property for the hosttype
8efdc76 (#5274) Tests for hostprovider removes comments
28e5772 (#5304) Use internal_name rather than real_name for maillist provider
3003719 These regular expressions will not match anything. pkgutil doesn't output anything that can be matched.
6c7290b (#5079) Refactor and cleanup mcxcontent provider
c643e98 (#5079) Move methods around to make it clearer whether they're public or private
2725fb3 Add comments that explain what we are ignoring in the package and remove legacy output
143fc74 Ignoring lines from use_gpg and catalog fetching
69a3451 Adding patch from Rudy Gevaert to fix not installed detection
b753d83 Fixed #5288 - Changed report default to true
ccc944f Fix #4339 - Locally save the last report to $lastrunreport
8ab1aba Fix #4339 - Allow puppet apply to save last run summary
4d31430 Fix #4339 - Save a last run report summary to $statedir/last_run_summary.yaml
b0acb02 (#3747) Add specs for upstart provider
2b772f7 (#3747) Implement upstart provider
6f1416d Fix #4904 Mounts shouldn't remount unless they are ensure=>mounted
bf11e7c Maint: Move "Local-branch:" info below "---"
04515cf (#5198) Added a spec test for new TB unit
631c5a8 Maint: Add "Local-branch:" info to mails sent by "rake mail_patches"
2ec1b55 Maint: Added missing requires to fileserver.rb.
f0a1467 Maint: remove unnecessary stubbing from agent_spec
5c24579 maint: prevent fork bombs by disabling ActiveSupport's Kernel.daemonize
f8d1427 maint: First draft of cert inspector
4506dfe (#5150) Make fact REST terminus configurable to connect to inventory service
71a0cea (#5198) add terabyte support to tidy type's size parameter
91ac162 (#5198) add gigabyte reference to docs for tidy type's size parameter
cfe2025 Maint: Remove Indirector::Request objects from HTTP Handler and API V1
3d32fe8 (#5166) Inventory service is now searchable by timestamp.
1f80cc6 Refactored Puppet::Node::Inventory::Yaml tests in preparation for adding freshness check
6c11601 Refactor Puppet::Node::Inventory::Yaml in preparation for adding freshness
fb5f859 Fix #5164 Change Facts timestamp when they are received by the master
5f0cf4e Maint: Don't use a stub for a Facts object in the compiler specs
90af920 Maint: spec/unit/indirector/catalog/compiler_spec.rb wouldn't run by itself
5bf19e4 [#4894] Randomize port on webrick tests
45a9a97 (#5132) Provide a query REST interface for inventory
2c98db6 (#5148) Fix failing spec due to timezone
c2ea112 (#5148) Add support for PSON to facts
7d35a47 Fixed to #5108 - Change default of service hasstatus property to true
4d1681e (#5062) Add envpuppet helper script to ext/
f2537d8 Puppet-load: better and safer error reporting
ce1865f Fix #5023 - puppet-load multiple nodes support
efeb2f4 Make --mkusers work on OS X, we now find unused uid/gids if unspecified like other platforms.
3c44121 [#4590] SimpleGraph is slow
6dd1930 Fix test failures that fixing #4726 exposed.
ce9bf1e Modified the error message that is generated when a class, definition, or node occurs in a conditional construct so that it contains the proper line number.
6b27850 [#4657] Customer-supplied .rb files are not compatible with multiple environments or staleness check
25048ec [#4685] Classes, defines, and nodes allowed inside of non-evaluated conditionals
1ba536e [3782] Test isolation problem in test/ral/providers/cron/crontab.rb
df088c9 [4638] Cleanup of plurals and inheritance relationships in AST
50fd9b7 Fixed issue #4570 (Race conditions when serializing objects to YAML).
4da88fb [#4496]+[#4521]+[#4522] Add structures to the AST to represent type definitions (classes, definitions, and nodes).
caca187 Moved perform_initial_import from Puppet::Resource::TypeCollection to Puppet::Node::Environment.
6b1dd81 [#4472]+[#4483] Moved type-name resolution out of Puppet::Parser::TypeLoader.
6dbd477 [#4397]+[#4344] Move type-name resolution out of Puppet::Resource into the AST resources.
d026bb7 pkgutil provider: Using the --single option which speeds up execution.
ec2a03c pkgutil provider: The path to the admin file is /var/opt/csw/pkgutil/admin
0fc2aa6 pkgutil provider: Correcting a typo in a message.
e02ba01 Using --single in the pkgutil provider.
fc18591 Adding pkgutil support.
9f365b1 Fixed #4258 - Added pkgutil package provider
83d9874 Use the name in the search path for looking for metadata
70c293a Fix for environments in startup script. - Dropped the forced --manifest switch in the suse startup script to allow for environments to re-define this. Otherwise, environments will not work as puppet override configuration with command line arguments.
62bc09e Redmine: 2474 - Fix for mount fstype documentation
7faf27c [#4064] Modify confine to also allow a message and a block containing the test.
e4b3aac [#4063] Add confine to describe block that depends on ActiveRecord
97936c6 [#3921] Add facts_terminus setting to Puppet settings
db39b7c [#4026] When --use_cached_catalog is specified on a puppetd run actully use the cache
4286839 [#4001] Added explicit check and error message when creating a file if parent doesn't exist
34d1897 [#3835] Fixed recursively absent directories improperly managing their files
9d0d94c [#3804] Fixed one failing spec for RackREST
da66e16 Fixing #3651 failing to pop comment stack for some constructs
069bf1b Fixed require warning documentation
23431da Fixed mcx documentation error
705cfe1 Documentation fixes
0a0923c [#4006] Fix test failures caused by reverting ticket 2890
8faa466 [#3866] Rename the method metaclass to singleton_class to avoid the deprecation warnings from Rails ActiveSupport
53e3610 Bug 3731. Applied Fix suggested by Doug Warner to always flatten out the array
b9aba7c maint: Have 'rake spec' output in color
3d7168b Fix for #3107 Changing users on AIX
5716028 Fixes #3663 - It should be possible to list signed hosts only
d71bd68 Updated CHANGELOG for 0.25.5
d88b357 Fixes incorrect line in partial CRL fix
dec84e5 Fixed documentation issues exposed in #3772
4daf8c3 Updated CHANGELOG for 0.25.5rc3
9214400 WIP - trying to fix #3460
9d3e98b Minimal footprint fix for #3751 (serialization 0.25.5 <-> 0.24.8)
d481340 Updated Template documentation link
5a1a45c Update Red Hat spec file for 0.25.5
2257605 Updated CHANGELOG for 0.25.5rc2
5258a0a Fixing #3533 - Removing all transaction cleanup
bcde541 Fix for #2910 -- Tidy/matches is too tricky to use
5abe571 Bug #3451: Don't leak the terminus class setting from Puppet::Resource::Catalog's spec
ebd924c Fix to the fix for #3295
ce233aa Write ssh_authorized_keys as user
6739bab Fix for #3558 -- source file reading speedup
b0e3c61 Fix for #3556 Plussignment value melding
8a30495 Fixed #3655 - Puppet doesn't find installed packages with portage provider
e4130af Fixed #3672 - Error message on duplicate fileserver mounts incorrect
1275a47 conf/redhat: Add notifempty to logrotate config
134204d Fixed stored configuration documentation
1aa98a6 Fixes #3653 - Changed default factpath value to better reflect plugins in modules
44f6d64 Partial fix to #2837 - changed warning message to debug
3a1b178 Fix #3555 - fix state of purged lists
f6046ab Fix for #3577 -- to_yaml parameter in 0.25.5rc1
f351e2d Renamed all references to Reductive Labs to Puppet Labs
cf7e696 Updated Rake tasks to no longer load puppet.rb
b93924e Fix #3540 - name methods correctly
9bc2f28 Fixes #3295 - generate() now sets the working directory to the directory containing the specified command.
3ee6834 Added YARD task
99818ef Update man pages and partial doc fix to #3491
f988af3 Fixed #3532 - Typo in lib/puppet/ssl/host.rb
f0e12e5 Fix #3496 - suppress transaction debug message
0eea2f5 Updated version and CHANGELOG to 0.25.5rc1
57ae381 Modify SuSE spec file for 0.25.x and correct shebang lines for puppetd/puppetmasterd
d90ec79 Fixes #3460 - Makes Puppet FHS compliant by moving /var/puppet to /var/lib/puppet
ae0b0bf Fix for #3101 (bug in MRI 1.8.7)
9db066b Fixes #3419. OS X 10.6 Ruby doesn't set supplementary groups
306d082 Revert the guts of #2890
4eea77a Fail gracefully on packages that don't have the HOMEPAGE variable set (e.g. dev-lang/php).
f5b8494 Fixed #3443 - Typo in mount type
b0ef2c6 Fixes #3135 - darwin doesn't support 'mount -o remount'
7018cf5 Adding :catalog_terminus setting
978ab8a fixing obsolete comment in puppetd
6d13d0d Adding support for only using cached catalogs
bc28715 Refactoring Configurer to enable the next feature
ba43d7b Fix for #3366 - --tags '' treated as boolean 'true'
5ab5e8a Supressing warnings (not really failures) in test/unit
e4df0b0 Fix test using wrong Puppet util filesetting group
eeb3d74 Mock user in SUIDManager tests
9ea27db Removing resources generate tests
218e3e9 Removing old test for service/debian provider
1556938 Replace test/unit file write test with spec
2defc00 Fix for #3424 and tests to prove it.
44798b9 Fixed changelog Rake task
5d10f65 Fix #3155 - prevent error when using two matching regex in cascade
fbedb99 Fixing #3148 Settings#without_noop when run with no noop setting
389c77b Another trivial follow-up fix for #2604: invalid path to zaml.rb
56b5753 Fix inefficient SimpleGraph#matching_edge
4b2b9eb Fix #3229 - use original value in case/selector regex matching
19863c0 Fix #2929 - Allow checksum to be "none"
fd76142 Fixed puppetlast typo
3b4e782 Follow up for #2604, debug msg left behind.
e44430b Fix for #2604 Pure Ruby yaml generation
74cd55f Fixes #3113 - When importing a manifest puppet needs to chill
7ec50a7 Fixes #3387 - Handle path elements with ticks and spaces
d561a98 Fix for #3412 install.rb should not put "." first in the tmp_dirs
751df45 Fix #3186 - require function set relationship only on the last class
a1d216c Fixed the return types were valid, and removed the copy paste error with the exception logic
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.11
===
e158b26 (#9793) "secure" indirector file backed terminus base class.
343c7bd (#9792) Predictable temporary filename in ralsh.
88512e8 Drop privileges before creating and chmodding SSH keys.
2775c21 (#9794) k5login can overwrite arbitrary files as root
2.6.10
===
ec5a32a Update spec and lib/puppet.rb for 2.6.10 release
fe2de81 Resist directory traversal attacks through indirections. (CVE-2011-3484)
243aaa9 (#7956) Porting cron tests
3e3fc69 (#7956) Port resource acceptance tests
2.6.9
====
db1a392 (#7506) Organize READMEs; specify supported Ruby versions in README.md
381fa40 (#6418) Make test 64118 more portable
98ba407 (#7127) Stop puppet if a prerun command fails
6996e0b Do not needlessly create multiple reports when creating a transaction
caca469 (#4416) Ensure types are providified after reloading
413b136 (#4416) Always remove old provider before recreating it
d866ce1 Cleanup indentation, comment, and unused code
98f58ce (#2128) Add WARNING for node_name_{fact,value} descriptions
1cd848c (#2128) Whitespace only reflow commit
d9b5c1a (#2128) In-line docs for node_name_{fact,value}
3f0dbb5 (#650) Allow symlinks for configuration directories
c260cf1 Fix acceptance tests not managing their masters
1c70f0c (#2128) Add support for setting node name based on a fact
c629958 (#2128) Get facts before retrieving catalog
cd4fe14 (#2128) Add the ability to specify a node name
8ebec1e (#7193) Fix path issues with acceptance tests that call old shell tests
16b2311 (#6885) puppet agent fingerprint requires --verbose to return a value.
a00fd25 maint: Refactor specs in preparation for making node name more flexible
75e2764 (#5318) Always notice changes to manifests when compiling.
4a5e99d (#7681) Add an acceptance test for resource refs with array variables
646919e (4123) Fix test for 4123/4 on old egrep in cent4
8b76be3 (#3836) External nodes should only capture stdout
8f907f2 adding test for ticket 7139
90eb937 (#7139) Accept '/' as a valid path in filesets
1b2a7d9 case seems needless here as there is only two opts, also the rest of the file seems to use if so this should make thin
729336e (#6845) Mount writes incorrect vfstab entries
16cf1ac (#6442) Be able to start agents --listen without namespaceauth.conf
0352402 (#3420) Nagios "name" attribute does not output correctly
f656818 (#4487) When setting environment on a host, ensure it is a string.
2cce326 add test for ticket 7101
c306db2 (#6487) Add some testing for OS X version support in DirectoryService provider
0008b63 (#6487) Directoryservice provider will fail in future OS releases
34f9f41 Maint: Fix a #4655 introduced log inconsistency
6b18f8f Move acceptance tests from puppet-acceptance repo
9a5bf6e Fixed #7166 - Replaced deprecated stomp "send" method with "publish"
656eff8 (#4655) Allow stage to be set using a default class parameter
7f658e6 vim: Initial ftplugin and indent support
ccbe9f3 Fixed #6681 - Remove --force-yes option from aptitude is used
2.6.8
=====
c1edcb2 add test for ticket 7101
db26326 Move tests from puppet-acceptance repo
bee1ef7 Updated CHANGELOG for 2.6.8rc1
8b7444d (#2331) Remove darwinports pkg provider, replace with rewritten macports provider
65c4e14 Fixed #7082 - Added system support for groups
b7f4ff7 (#7018) Give more context on the service type's assumptions. Wording tweaks.
bb19dea (#7018) explain internals better in service provider documentation
23c9663 maint: Fix sqlite3 require to really be optional
4b73d41 maint: Fix sporadic sqlite error
54b9f5d (#6818) Stop from getting Rails 3 named_scope deprecation warning
e493f8a (#6856) Copy dangling symlinks with 'links => manage' File resource.
1e4968e (maint) Indentation fixes
99d78f2 (#6490) Add plugin initialization callback system to core
5d1cb02 Fix #4339 - Locally save the last report to $lastrunreport
306aa30 Fix #4339 - Save a last run report summary to $statedir/last_run_summary.yaml
9bb3018 Fixed #3127 - removed legacy debug code
d2bacd3 Fixed #3127 - Fixed gem selection regex
1b66c28 (#5437) Invalidate cached TypeCollection when there was an error parsing
0675c9a (#6937) Adjust formatting of recurse's desc
2cdadf9 (#6937) Document the recurse parameter of File type.
647a640 (#6893) Document the cron type in the case of specials.
87ca313 (#5670) Don't trigger refresh from a failed resource
f5aabf5 (#5908) Add support for new update-rc.d disable API
37f9ca0 (#6862) Add a default subject for the mail_patches rake task
9a4de12 Fixed #6256 - Creation of rrd directory.
7c60db5 (#5477) Allow watch_file to watch non-existent files, especially site.pp
7761acb (#5221) Add test for fix to fileset with trailing separator
357514c (#5221) Fix fileset path absoluteness checking with trailing slash
f8941b8 (#4769) Fix negative timeout support for newer rubies
a29c7fd Fixed #6562 - Minor kick documentation fix
df20513 (#6658) Propagate ENC connection errors to the agent
08115c0 (#4884) Remove typo from spec test
f2c771b (#4884) Modify tests to pass on non-OS X systems
ec1aa19 (#4884) Revise new exec tests, add a few more
196294a (4576) - if ENC declares invalid class, it is logged at warning.
0d2d6f3 (#4884) Add an shell provider for execs
d2e911a (#4884) Fix Test::Unit exec tests
fa0cfc6 (#4884) Break the exec type out to have a posix provider
c86a980 (#4884) Add consistent path validation and behavior
77fbf7f (#4884) Add expand_path to requiring the spec_helper
7ec9057 (#4884) Autorequire shared behaviors and method to silence warnings
acc99ba (#4884) Fix whitespace
6a4d291 (#4884) Get rid of open3 require since it wasn't being used
3e7ebbb Fixed #6554 - Missing $haveftool if/else conditional in install.rb breaking Ruby 1.9
fddc165 (#5814) Improved cron type specs
f2dfee6 (#5814) cron_spec shouldn't depend on cron provider
2.6.7
=====
17f673d Updated CHANGELOG for 2.6.7rc1
852fb97 (#5073) Download plugins even if you're filtering on tags
4f34dbf Fix #5610: Prevent unnecessary RAL lookups
9781032 Revert "Merge branch 'ticket/2.6.x/5605' of git://github.com/stschulte/puppet into 2.6.next"
25926d1 (#6723) Fix withenv environment restoration bug
093f162 (#6689) Remove extraneous include of Puppet::Util in InventoryActiveRecord
4c19299 Remove extra trailing whitespace from lib/puppet/resource.rb
ff9e242 (#5428) More fully "stub" Puppet::Resource::Reference for use with storedconfigs
0262633 (#6707) Fix typo in rest_authconfig.rb
8858e40 (#6689) Make inventory_active_record terminus search quickly
285c4cc (#5392) Give a better error when realizing a non-existant resource
cd5deda (#2645) Adding a less-stubby test to verify the "system" attribute's behavior
531e258 maint: Remove serialization of InventoryFact values
3489412 maint: Rename InventoryHost to InventoryNode
4bd5493 Fixed #2645 - Added support for creating system users
a3f2357 maint: Remove spec run noise
7764412 maint:Refactor of mount provider integration tests
880d0c6 (#6338) Support searching on metadata in InventoryActiveRecord terminus
f836366 (#6338) Implement search for InventoryActiveRecord facts terminus
8ce30c8 (#6338) Add an InventoryActiveRecord terminus for Facts
1ef83cb Added integration tests for the mount provider
64440e5 (#6513) Propagate the environment when doing variable lookup in settings
92dffb2 (#6513) Adjust P::U::Settings test name to reflect what it tests
5ef1031 (#6632) Adding a new mount no longer causes error with umount
bd5517d Adjust Darwin mount provider tests to pass on Linux
9d2fceb Maint: Begin adding integration tests for the mount provider
23d1c03 Maint: Added the ability to replace the behavior of Puppet::Util.execute with an arbitrary code block for ease in spec testing.
455a891 (#5794) create reports directory when creating host specific directory
1b1e803 (5724) Prep for deprecation of DESTDIR
f4a0af1 Refactoring duplicate code and logic in prep for DESTDIR deprecation.
7a00d6b (#6606) Inline docs: Document all autorequire relationships
e3aec14 (#5148) Fix failing spec due to timezone
8bd80a9 (#5148) Add support for PSON to facts
c3baa28 (#6338) Remove inventory indirection, and move to facts indirection
6c53eb3 (#6445) Fix inline docs: puppet agent does not accept --mkusers
4e29f43 (#6541) maint: whitespace cleanup on the file integration spec
b907ba3 (#6541) Fix content with checksum truncation bug
422399b (#5466) Write specs for output of puppet resource
8cc390c (#5466) Monkey patch Symbol so that you can sort them
24eacb7 (#5466) Fixed puppet resource bug with trailing ,
743e039 (#4922) Don't truncate remotely-sourced files on 404
bb69011 (#6338) Remove unused version control tags
e2a5085 Maint: Align tabs in a code block in the Augeas type.
65a5496 (#6509) Inline docs: Fix erroneous code block in directoryservice provider for computer type
ea9f1f0 Maint: Rewrite comments about symlinks to reflect best practice.
94f8ead (#6509) Inline docs: Fix broken lists in Launchd provider.
c80a77d (#6509) Inline docs: Fix broken code blocks in zpool type
27863c3 (#6509) Inline docs: Fix code blocks in service type.
f4034f7 (#6509) Inline docs: fix broken code blocks in schedule.rb.
6f6c4b5 (#6509) Inline docs: Fix broken code block in file type (content attribute)
a949a83 Revert "(#6309) Ensure the correct device is mounted when managing mounts"
23a510a (#4914) Improved stubbing in mount/parsed_spec tests.
ac2262d (#3999) Allow disabling of default SELinux context detection for files
23eb77d (#6322) --noop should not suppress error codes
439115e (#6499) Make puppet respond identically to -h and --help
23b7119 Maint: Add an assertion mechanism to Puppet
e3dfe41 (#6418) Recursive files shouldn't be audited
0e9858f (#6407) Fix spec test hang with Mocha >= 0.9.11 in zlib testing
309b932 (#5552) Display help when no subcommand is given.
de6a205 (#5552) Clean up subcommand handling inside puppet cert.
bb31c3d (#6376) Add test case for facts find request
2ecf913 Revert "(#5935) Allow functions to accept negated values"
c57c508 (#4914) Improved parsed_spec for mount
ec33a09 (#4914) Remove mount specs
e854205 Remove pending tests from parsed mount provider
6cb365a (#6309) Ensure the correct device is mounted when managing mounts
d1f1858 (#6376) Add support and testing for _search GET requests
3b41d44 Clean up whitespace, and commented out code in parsed mount provider
a7cebf8 (#6337) Fix Ruby warning on 1.8.6 about "future compatibility"
8a48560 (#5150) Make fact REST terminus configurable to connect to inventory service
e6870f6 (#5166) Inventory service is now searchable by timestamp.
2d2f9ab Maint: backport timestamp accessor for facts from 2.7 branch
fa0ed63 Refactored Puppet::Node::Inventory::Yaml tests in preparation for adding freshness check
67f24e4 Refactor Puppet::Node::Inventory::Yaml in preparation for adding freshness
23fc4db (#5132) Provide a query REST interface for inventory
e3c59df (#5935) Allow functions to accept negated values
7cb884e (#6346) Move the trap calls onto Signal so they're easier to stub
b5bae9f (#6331) Remove final special :trac: link from the file content property
4d25d90 (#6331) Inline documentation: Fix rotted links pointing at the Trac wiki
b25d9e4 maint: make rspec exit with status 1 when there are failures
5c26f68 (#5516) Rebuild parser.rb after merge.
e512e3e (#5977) fix spec test failure when new applications are introduced.
b5b5923 misc: ast_context has two arguments, not one.
414e3a5 Fix #5516 - Hashes can't be used in selectors
c373b62 Fix #6269 - Hashes only work with two levels of access
9090507 Fix #6267 - puppetdoc embedded links to puppet entities are not hyperlinked
b4a171e Fix #5720 - puppetdoc misses some class comments
cfa0c32 Fix #6281 - Make sure puppetdoc analyzes all files
48bc7d0 Fix #6280 - puppetdoc crashing on string interpolation
0b7faa6 (#6270) Fix formatting in split function's doc string
637e139 (#6270) Fix formatting in regsubst function's doc string
e9ee621 (6130) Change header level on metaparameter reference
d6e4ffe (#4914) Specs for mounted? match new behaviour
f534470 (#4914) Add specs for modified mount provider
b753038 (#4914) Add specs for modified mount type
9f40608 (#4914) Update property blocks
fd111f2 (#4914) Query property_hash for mountstate
2884660 (#4914) Prefetch mountstate
ade951a (#4914) Join lines for better readability
8b98526 (#5662) Fixed tests that didnt stub key_attributes
02b3111 (#5605) Prefetch doesnt work with composite keys
2a0c970 (#5662) Parsedfile doesnt work with mult keyattr
35dd070 (#5661) Creating types dont work with >1 namevar
2.6.6
=====
d24e32a Update CHANGELOG and version for 2.6.6rc1
7c2a980 (#6541) Fix content with checksum truncation bug
63e911f (#6418) Recursive files shouldn't be audited
2.6.5
=====
30fa41d Updated CHANGELOG for 2.6.5rc5
b481321 (#6337) Fix Ruby warning on 1.8.6 about "future compatibility"
dcce45c (#6353) Restore the ability to store paths in the filebucket
0450197 (#6126) Puppet inspect now reports status after run completes.
960890f (#6364) Adjust mis-translated regex in mount provider for AIX
9e0f9c5 Updated CHANGELOG for 2.6.5rc4
664ef67 (#3646) Fix the documentation fix for `puppet apply --apply`
4b6519a Updated CHANGELOG for 2.6.5rc3
7ef2fbf Updated fix for #3646 - apply / compile documentation
193016d (#5977) fix spec test failure when new applications are introduced.
c08fc1b Updated CHANGELOG for 2.6.5rc2
1f89906 (#6257) Speed up PUT and POST requests under rack
70a43c4 Updated CHANGELOG and version for 2.6.5rc1
f108f03 (#6018) Nick F's --help text for puppet inspect.
04ea826 (#5823) document the not-an-API status of set_run_mode
4ff5769 (#5823) run mode can now be set dynamically...
bddfa1e (6114) Update the audit metaparameter for 2.6.5.
ac8d316 Fix for #5755 -- making zaml serialization robust over projected objects
c912a2a (#4139) hook log autoflush into global defaults
f9e2e2b Augmentation of tests for prior commit
392504a Fix to fix for #5755 -- backref serialization issues in zaml
a732a15 Fixed #5564 - Added some more fqdn_rand documentation
f279f2c Fixed #4968 - Updated list of options turned on by --test in documentation
ce5a2bf (#5061) - allow special hostclass/define variables to be evaluated as defaults.
fd73874 (#6107) Fix an error when auditing a file with empty content
530496b Remove already initialized constant warning from file_spec.rb tests
76788f8 (#5566) Treat source only File checksums as syntax errors when used with content
d657292 Rename variable used in File type validation to be more clear
3398139 Remove invalid "timestamp" and "time", and add missing "ctime" File checksum types.
6c93eb2 Remove order dependency when specifying source and checksum on File type
3a125d4 Bug #5755 -- ZAML generates extra newline in some hash backreferences.
50c12e5 bug #5681 -- code fix to handle AIX mount output
139760b Bug #5681 -- parse AIX mount command output.
2f74d83 Spec for #5681 to allow parsing of AIX mount output in mount provider
878f266 Fixed #6091 - Changed POSIX path matching to allow multiple leading slashes
eb97aa5 Bug #6091 -- test leading double-slash in filenames are allowed.
1bfc9a0 Fixed #6071 - Fixed typo and improved exec path error message
c50a48e Fixed #6061 - Allowed -1 as password min/max age
bf44e72 Bug #6061 -- verify that negative {min,max}_password_age are accepted.
af1c1fe Feature #5855 -- fix withenv call in freebsd package provider
d871641 Feature #5855 -- undefined method 'withenv' in FreeBSD package provider.
f1ab588 Fixed #6009 - nested member list vs directory service group provider
86a2a00 (#5944) Remove documentation of define() when used on nodes, as it is not a supported use of this function.
2b9f653 (#5944) Further edits of inline defined() documentation.
5d108e8 (#5944) Improve documentation of defined() function
7d38ab2 (#5594) Update documentation of exec resource type.
67e1bba (#5931) Prevent errors when calling insync? on audited properties
0f9d236 Maint: Removed dead code from resource harness.
0765afb Maint: Rename misleading insync? method in file provider
0084b08 (#5548) Specify return values of manual status commands in service type description.
dd332f6 Fixed #6002 - Added note about function execution
3cfbd07 (#5045) Cleaning up some tests and code
a2036ea (#5045) External node classifiers should be able to specify params for classes
18ca97b (#5045) Adds support to resource/type to also accept a param hash
70630b9 Fix #3165 Ralsh (bin/puppet resource) can't manage files
1fd3600 Fixed #3646 - Added documentation for compile and apply to man page
ae48634 Fixed #5914 Removed genconfig = true from genconfig output
7e7f342 Fixed #1657 - Added note about target file
069f29b Fixed #2096 - clarified option modification and tested it is working
66b442b Fixes #5916 - Cleanup of unused doc methods and documentation
9b74968 Modified rubydoc in lib/puppet/util/command_line/puppetca to fix inaccurate description of --clean.
e58f5dc Fixed #5742 - Removed legacy fqdn option from documentation
4d1b51f Fixed #5167 - misleading documentation in the defaults of [main]
c1b5c7f (#5913) Fix Puppet::Application.find constant lookup behavior
7b3b56e (5977) Puppet::Applications can be loaded from multiple paths.
f9bfb96 (#5900) Include ResourceStatus#failed in serialized reports
79b6332 (#5882) Added error-handling for bucketing files in puppet inspect
17843d5 (#5882) Added error-handling to puppet inspect when auditing
1a6fab2 (#5171) Made "puppet inspect" upload audited files to a file bucket
a7cd185 Prep for #5171: Added a missing require to inspect application.
71ac9cf Locked Puppet license to GPLv2
abc6256 (#5838) Support paths as part of file bucket requests.
002f9f1 (#5838) Improve the quality of file bucket specs.
94d7179 (#5838) Make file bucket dipper efficient when saving a file that already exists
89f5692 (#5838) Implemented the "head" method for FileBucketFile::File terminus.
9cfd3d5 (#5838) Reworked file dipper spec to perform less stubbing.
c514c64 (#5838) Added support for HEAD requests to the indirector.
2b9b7a5 (#5838) Refactored error handling logic into find_in_cache.
08561b2 (#5838) Refactored Puppet::Network::Rights#fail_on_deny
87c5c30 (#5910) Improved logging when declared classes cannot be found:
4efc98a maint: Remove unused Rakefile in spec directory
a002231 (#5171) Made filebucket able to perform diffs
8f314f2 (#5710) Removed unnecessary calls to insync?
e270086 Prep for fixing #5710: Refactor stub provider in resource harness spec
c57a677 Maint: test partial resource failure
8aa8b9d (#5799) Simplify report dir creation
2d88844 maint: Add vim swap files to .gitignore
3d3baec maint: Remove rspec options from the Rakefile
df65304 maint: Inspect reports should have audited = true on events
4c9eca1 Maint: Added "skipped" to the YAML output for Puppet::Resource::Status
717670f (#5771): Fix spec failures associated with rspec upgrade
52760a4 (#5771) Upgrade rspec to version 2
7603b05 maint: remove stray debug statement.
7661ba8 maint: Prune #inspect methods on various objects
80bfb54 (#5758) Verify that report events are correctly created
de85f8d Prep work for #5758: set audited=true on all audit events
e162da9 Prep work for #5758: clean up initializer for Puppet::Transaction::Event
06a8d1e Fix #5698 puppet inspect shouldn't report of attributes of deleted files
1f72c31 (#5715) Added attributes resource_type and title to Puppet::Resource::Status.
a6cd736 (#5715) Removed attribute source_description from the YAML representation of Puppet::Resource::Status.
98db2da (#5715) Removed unnecessary attributes from YAML of Puppet::Transaction::Event.
bd4a8a1 (#5715) Make certain report attributes always present.
716ee1c (#5715) Changed the type of metric names to always be strings.
037eac4 (#5715) Add status attribute to reports.
e4a2e04 (#5715) Made the report "calculate" methods strictly functional.
71db5be (#5715) Made the changes/total and events/total metrics always present
a4e40f4 (#5715) Refactor in preparation for adding a status attribute to reports.
15dda94 (#5715) Added total time to inspect reports and made inspect metrics more consistent.
d1bcdec (#5715) Removed Puppet::Transaction::Report#external_times from YAML output.
1550bbb (#5715) Added total time metric to apply reports.
4cc42cd (#5715) Removed redundant attribute Transaction::Event#version
1907650 (#5715) Removed redundant attribute Resource::Status#version
e596a57 (#5715) Removed Puppet::Util::Log#version.
908e0e0 (#5715) Removed the unused attribute Puppet::Transaction::Event#node
0e39ec5 (#5715) Removed Resource::Status#skipped_reason. It was never used.
b765f0e (#5715) Prep work: Fixed add_statuses in report_spec.
8631709 (#5723) Fix failing type/package specs
76fe2b3 Implement #5168 and #5169 ctime and mtime are properties
d11ae78 [3782] Test isolation problem in test/ral/providers/cron/crontab.rb
4d3030c Modified the behavior of Puppet::Resource::Status as follows:
7fff780 (#5408) Reworked ResourceHarness so that code is clearer and all behaviors are tested
d516f63 (#5493) Add report_format, puppet_version, and configuration_version to Reports
093c45f (#5375) Rework puppet apply to use configurer.run
e99a3ea Fix #5566 none, mtime, and ctime checksum types can write file contents
d74e8e1 maint: Fix ActiveRecord confine issue
6daeb16 maint: Fix a test that was missing a require
5db696b maint: Fix tests that don't run on their own
7f4e058 (#4487) Fix environment column in hosts table
3ac50fa maint: restore plugin handler safety
f38c36c (#5408) Attributes can be both audited and managed
54a1025 maint: missing stub
1d3192e maint: missing stub
1aa8157 maint: missing line and filename stubs
5e5ee97 maint: Fully stub partially stubbed test.
3d7c8d0 maint: remove Puppet.settings stubs
52fba89 maint: test was expecting Catalog.find too few times
8c134b6 maint: broken test not failing due to over-eager exception catching
3e59277 Fix #1757 Change file mode representation to octal
84bf02e Bug #5423: This moves the home directory property before the uid property, thus minimizing room for damage when usermod is in use.
1131ad7 (#4943) Add puppet inspect application
e005cc7 maint: Remove bogus mongrel test
c908fdb (#5261) Fix #5261 Don't escape Unicode characters in PSON
b27e9b4 [#5081] Revert "Fix #4349 - Parsing with ignoreimport=true was always loading site.pp"
af6e08c (#5304) Use internal_name rather than real_name for maillist provider
2.6.4
=====
76890a5 Revert "(#5304) Use internal_name rather than real_name for maillist provider"
19f3879 Disable remote ralsh by default
eee1a9c (#5424) Ship auth.conf as part of installing from source
779fea8 (#5304) Use internal_name rather than real_name for maillist provider
83f878e Renamed Reductive to Puppet
2.6.3
=====
53bb805 Incremented CHANGELOG for 2.6.3
184733c [#5322] (#5322) Remove spec file that adds little value and causes failures
178c2a6 Fix test failures that fixing #4726 exposed.
74b6c09 (#4726) Fix RRD legacy support
8662056 Fix for #4279 -- mount detection on HP-UX
fbb096a Fix for #5055 -- adding to_sym to Puppet::Node::Environment
b2ff6a5 Fix for #5298 -- Collections need to do type lookup
1ce00dc Step towards [5298] -- cleanup indentation, etc. in AST::Collection
722608b Fixed #5287 - Schedule documentation is incorrect
c8b6fb5 Fixed #5296 - test warnings messages
d221c05 (#5297) Fix schedule tests that were missing stubs for Time.now
f2fd0d1 Fix for #5273 -- user resource constantly resetting password age
544dcf8 Fix #5289 -- Bad copy/paste changes message on test failure
2.6.3rc3
========
126681f Updated CHANGELOG for 2.6.3rc3
b15231d Fix for #4299 -- Don't require which
ea435a4 Fix #5020 - Prefer finding node name from REST uri over certname
a097b93 Fix for #4894 -- retry tests if port is in use
ee61b4e Fix for #4955 -- Race condition & memory leak in Puppet::Util
f57425d Fix #4921 - race condition in Parser Functions creation
9604f1c Fix #5252 - line number mis-attribution during parsing
cc5224c Maint. fix for test broken by 00eedac5
5f7d0fb Fix for #2568 -- Add a dbconnections option to set AR pool size
ba4d22b Maint. Removing code for which no CLA has been signed
4a3d5d7 Reimplementation of functionality removed by prior commit
235d641 Refactor for CLA
9ba0c8a Fix #4923 - close process race when truncating existing file
cb16d3d Puppet-load: better and safer error reporting
1d26742 Fix #5023 - puppet-load multiple nodes support
00eedac capture stderr from exec resources
4cbceab (#4573) FreeBSD service provider now supports versions <7 and >8
06c8748 Fix #3808 - puppetdoc should use --force-update only if RDoc supports it
6e6712b [#4813] Remove dead code from puppet/rails/host.rb
956296a Fix #4911 - Do not generate doc for standard RDoc parser generated object
4fa24bb Fix #5127 - error when accessing array elements
abb8c66 (#5242) Fix schedule specs that fail near daylight savings
ec667fd Kludge for #5206 -- port of fix for #3536 to yaml
9a3b584 (#5062) Add envpuppet helper script to ext/
aad7008 [#5225] Fix spec failure that depended on time change
21db472 (#5233) Randomize tmp dir paths
2.6.3rc2
========
244213c Updated CHANGELOG for 2.6.3rc2
76ac1f8 Fixed #5112 - Launchd Service broke in 2.6.2 with OS X 10.4 Clients.
776ea2a Fixed #5137 - Removed no longer required TOC references
31118fe Kludge for #5048 -- serialization compatibility with 0.25.x
65ef24e (#4534/#4778) -- Normalize parameterized classes
3b53bfc Fix for #5022 -- Escaped newlines should be elided
2.6.3rc1
========
e3fc5b9 Updated CHANGELOG and version for 2.6.3rc1
3c56705 Fix for #4832 -- Making PSON handle arbitrary binary data
e232770 Minimal fix for #4975 -- only call chage when managing password age rules
a090e86 Fix for #4963 -- Use correct commands for password expiry on solaris
2.6.2
=====
295c3be Updated CHANGELOG for 2.6.2
1d719be Fix for #4945 -- explicitly check os to supress man page installation
55417bc Reversion of 021d534482dd8edb863cb77d668ac3525362a0a6
a6e2bea Fixed #4919 - added parenths to fix error message:
2.6.2rc1
========
917c520 Incremented version to 2.6.2
900eae4 Updated CHANGELOG for 2.6.2rc1
1b6094d Fixed documentation typo
bdf12fe Fix for #4896 -- stray newline left over from removed diagnostic
e7424c6 (#4772) Update SuSE .spec file
0aaa742 Fixes #4792 (Duplicate definition since 2.6.1 upgrade)
ea49d13 Improvement to #4025: made spec tests work on all platforms
0b4ce08 Adds #3046 - support for password min/max age
e9f9d26 [#4783] (#4783) Fix RRDGraph report generation
34f87cf Add user account expiry to the useradd type and provider
a7fb9b1 Fixed #4025 (failure in launchd if certain plists are binary).
2573872 Fix for #4649 -- avoid unsupported features on non-posix systems
eb9279c Fix for 4273 -- revert b7e2580ab49ecdb67fc9b522829c005fc3750fbe
53a2bea Fix for #4804 -- escaped backslashes in interpolated strings
d12e477 Fixes #4863 (Missing "require 'webrick'" causes nondeterministic spec failures)
574812e (#4860) Add regression tests that would have caught bad params method
68947e7 (#4860) Fix wrong method name.. params seems to be renamed to parameters
021359b Fix for #4644: install.rb works properly on Windows
d057b90 Fix #4726 Update puppet rrdtool metric code to support modern rrd ruby bindings
66cf3a9 Fix #4226 - Prepend 'Puppet CA: ' to fqdn for default root ca_name
d54352a Port Puppet::SSLCertificates::CA test to rspec
effc6b8 Fixes #4852 - error messages involving Whits now mention Classes instead
3f99bd7 Fix #4267 - Create a backup before dropping permissions
6468f4e (#4763) Don't call a method that was removed in Rails 3 activerecord
79d5fde Fixed #4763 - Hardcoded ActiveRecord version
4798df3 Fixes #4822 -- Puppet doc -o option broken
99c1019 [#4798] Puppet doc manifests documentation mode broken
8cd1540 [#4692] undefined variables cause :undef to be passed to functions
06bf566 [#4787] Missing require causing failure
bba04e0 Fix for #4746 -- Newline goes at the _end_ of the line
9e17c25 Fix #4743: Allow the audit meta-parameter to accept both 'all', and :all
f950061 [#4716] ResourceTypeAPI exposes implementation details that are likely to change
8ff4b9a Fixed #4819 - corrected cron documentation
2b50f30 [#4771] Import of manifests with the same name only happens once
7b8cb74 Fix for #4708 - tagmail should allow . in tagname
6f229ee Minimal fix for #4631 -- set implicit classes as in 0.25.x
021d534 Fixed #3707 - rpm, like dpkg-query exits 1 if the package is not installed. Returning nil in this provider had the effect that on every run, puppet would end up calling yum erase . Returning the correct data structure resolves this.
216f663 Fixed Puppet Doc TOC generation
c3cb57c Fixed versioncmp function typo
898a170 Fixed Reductive references in LICENSE file
996f14e Documentation updates for Markdown conversion
2.6.1
=====
cad1e0f Updated CHANGELOG for 2.6.1
14f871d [#4756] addendum for #4756
9bdfe69 Fix for Bug #4756 - Providers no longer respect missing features Restored deleted lines from type.rb and reinstated unit tests
14b3340 Fix for #4736 -- preserve case of defined resources
bd973a2 Fix for #4637 --use of namevar missed in refactor
2.6.1rc4
========
efa834a Updated CHANGELOG for 2.6.1rc4
763e7cb Minimal fix for #4691 -- class name uppercased in $name
4a9c857 Fix for #4693 -- implicit stages should never be serialized
fa4d32c Fix for #4646 -- Missing stub
4d55c6e Fix for tests broken by fix for #4489 -- stub standalone
b397b69 Fix for #4489 -- apply was using the rest terminus
e91a8cc [#4462] uncaught Timeout::Error
4d36a51 Fixed alias metaparam docs error
b063635 Skip apt-listbugs and apt-listchanges when installing from puppet
e860907 [#4660] Avoid passing rake and autotest args to puppet tests
419e007 Fixed #4706 - logcheck patterns
f6c0265 Fixed queue require for #4555
07d0be4 [#4308] Remove puppettest from specs
9e69616 Fixed RSpec warning messages
8d24861 Fixed #4100 - Added http_caching to yumrepo type
8cd266e Added cost parameter to the yumrepo type
0056d41 Fixed extlookup documentation and spacing
e783a16 Fix for #4506 -- too much data being serialized
f59cfc8 Fixed terminus example documentation
690465e Fix #4615 - vim highlighting fails on slashes and colons.
078e4fd Updated man pages
7548c65 Updated Man page generation since move to Markdown
2.6.1rc3
========
8be1929 Updated CHANGELOG for 2.6.1rc3
81a2725 Fix for #4456 -- need to accept some mime-type aliases
c318558 Fix for #4489 -- apply was using the rest terminus
491c31d Fix for #4542 -- included classes weren't assigned proper stages
302d657 Fix for #4501 -- reports not generated in standalone
1ea4ccf Start server before agent
4c28079 [#4555] puppet queue tries to call code it hasn't required
d1150e0 fix #4528 - treat * as absent
20f4b90 Fix for #4518 -- classes not getting added to compiler.classes
57bb06b [#4545] Remove obsolete 'trac' specs
82b4f04 Maint. -- Fix test failures broken by previous commit
0c30754 Maint. Removing code at the request of the original author
3df0490 [#4298] Puppet apply prints an error if the file to apply doesn't exist
5d4f222 Fixed #4527 correctly for 2.6.1
1b3d782 Updated config.ru example for 2.6.1
2.6.1rc2
========
0aa27b5 Updated for 2.6.1rc2
252c9b8 Further RST to Markdown fixes for types, values, tests
1157e8d Updated all types to Markdown output
fef8800 Updated reference output to generate valid Markdown
79e0a2e Reformatting documentation from RST to MarkDown (#4509) Signed-off-by: Jes Fraser <jes@gadget.geek.nz>
62435e5 Rewrote functions documentation to Markdown
e4b2aa6 Removed legacy Trac code
8ddea2a Maint. Passenger fix broke a test
f43e87b Fix for #4476 -- rails calling yaml internals
a23d80a Fixes #4485 -- single quoted strings should not treat \n as new line
8e31b52 Passenger needs HTTP headers values to be string
037bb32 [#4404] Remove requirement for source on Parser::Resource::Param
0e4bc62 [#4364] Fix failing spec due to incorrect loglevel
3a6ca54 Fix #4458 - Do not dump the whole environment when instances can't be found
d909827 Fix for #4465 -- earlier "feature" patch broke ldap
47005aa Maint -- tests need to respect RFC-952
6aac8f0 [#4467] Make Puppet Master respect facts_terminus settings
1cba9a7 added md5 support as requested in http://serverfault.com/questions/166199/puppet-md5-sum-of-string
1dfd2b6 [#4381] extlookup shouldn't trigger reparses of .pp files
be2b1f3 [#4370] Fixes extlookup precedence getting overwritten between runs
03808fd Fixed #4364 - Reduced audit msg from info to debug
539b57c [#4347] run_mode was colliding with --mode for "puppet doc"
1faebdd [#4423] repair parameterized class instantiation
37568bd [#4423] class { shouldn't get stored on the namespace stack
449315a [#4397]+[#4344] Move type-name resolution out of Puppet::Resource into the AST resources.
daa801b [#4344] Temporary fix to stop agent from importing modules
00ebf01 [#4344] Fix for failing templates when module name matches file in local dir.
e32320e [#4336] "reportdir" was in the wrong section
0f9672a Fixed #4311 - Typo in defaults.rb
f54d843 Fix #4461 - attempt to fix another performance issue
2c21fae Fix for #4300 Solaris svc files need new pid filenames
83c2419 [#4284] Fix failing specs run as root due to missing puppet group
8237f68 [#4242] Fixed (removed) a broken unit test
d5ad0fb Removed eventual documentation line ... eventually came
871e6fd Fixed #4368 - Updated clean stored configs ext script for new config sections
cb64477 Updated version to 2.6.1
2.6.1rc1
========
ecf44e4 Updated CHANGELOG for 2.6.1rc1
bdfcac5 Update Red Hat spec file for 2.6.0
9f08e7c Feature: puppet-load - a tool to stress-test master compilation
ef9a4a6 Fix #4245 - default insertion of ACL is not thread safe
4065e81 Fix race condition in rack autoloading of request/response
3163932 Fix #4244 - Cached Attributes is not thread safe
7d42f77 JRuby doesn't implement Process.maxgroups
760e418 Fix #4349 - Parsing with ignoreimport=true was always loading site.pp
67bdf89 Fix #4348 - Puppet doc single manifest broken
13c71b9 extlookup() is a builtin
d38e522 [#4333] old optparse doesn't support default_argv=
86b0882 Fixed #4326 - Updated SUSE packaging
03313b8 Fix #4319 - source file url sent to the master is invalid
ac3a0d2 vim: highlight default parameters in definition/classes
be2141a vim: match collected resources.
c047c8d vim: added elsif
9569136 Fix for 4314 -- Need to allow '-' in class name for refs
636079f Fixed #4304 - Changed logging level for auto import message
000fd1e Fix for #4303 -- reverting to old escaping in '-strings
1d494a3 Tweak to fix for #4302--dangling ref to known_resource_types
2383050 Fix #4302 - Compilation speed regression compared to 2.6
63ec207 Minimal fix for #4297, with notes for follow-up
7ad7eb1 Fix #4286 - rename puppetdoc global module <site> to __site__
28bb195 Fixed yumrepo type deprecation wanring `
067a46d Temporary tweak to tests for #4242
9778f2a [#4242] Fixed recursion due to parents including their children
59a23d6 Fix for #3382 -- Empty classes as graph placeholders
865282a Fixed example config.ru
a0a63c3 Fixed network and indirection reference
64386cf Fixed Indirection reference
2.6.0
=====
db0b30d Updated CHANGELOG for 2.6.0
42a475e Fixing #4268 - manifests always imported
06fc40c [#4269] Undef variables interpolate to empty string
1288f8c [#4270] Force inherited classes to load into the correct environment
539d716 [#4287] Fix the undefined evaluate_match error when comparing functions
d2da1d4 Tweak to tweak to fix for #4233 -- ":" is valid in type names
bbc07f2 Bandaid for #4285 -- :name vs <namevar>
40e6f02 Tweak to fix for #4233 -- only accept word chars in types
2.6.0rc4
========
d87a2e3 Updated CHANGELOG for 2.6.0RC4
cf597d7 [#4233] Ruby regexps are not multiline by default, but Resource titles can be multiline
d6cbb21 Fix for #4234 -- ruby DSL fails on second resource
4822de3 Fix for #4236 -- Only interpolate $ if followed by a variable
b509032 Fix #4238 - if should match undef as ''
8c8c146 Minimal fix for #4243 -- import isn't thread safe
d319da4 [#4247] storeconfigs was calling Puppet::Parser::Resource.new with the wrong arguments
9f91540 [#4256] External nodes parameters can now be assigned to nodes
680dd1a Fix for #4257 -- problems resolving ::-prefixed classes
6e07a19 Fix #4262 - Puppetmaster used to log compilation time
5b68afe Fix for #4255 -- misleading diagnostic message
dd03ac9 Partial fix for #4278 -- the performance aspects
4ce33fd Fixed #4249 - Updated SUSE packaging specifications
91185c6 New man pages for 2.6.0
1cda7c5 Fixes errant Trac references in documentation
2.6.0rc3
========
f60b6a0 Updated CHANGELOG for 2.6.0rc3
9df87e9 [#4219] Install misses command_line dir, puppet $app --help fails
0422852 conf/redhat: Consistently pass pidfile option to daemon, killproc, and status
63bf037 conf/redhat: Update conf/init files for single binary
f72741f conf/redhat: Rebase rundir-perms patch
793d7b7 [#4213] -o option for setting onetime now works properly
2edf7fe [#3656] Serializing arrays of references
27d5a47 [#4215] Have rundir depend on vardir
06cc552 Fix for #4220 -- modules not implicitly loading their init files
2.6.0rc2
========
8747479 Updated CHANGELOG for 2.6.0rc2
fa74020 [#4209] catalog.resources should return resources
f5f9a38 Fix for #4210 -- missing require in CA
1c3e844 Minimal fix for #4205 -- incorrect Import loop messages
99d8323 Fix #4206 - import "path/*" tries to import files twice
a2115af Alt fix for #4207 -- serialize environments as their names
fe4dcd8 [#4208] Missing parameter breaks multithread compilation
2.6.0rc1
========
e028310 Updated CHANGELOG for 2.6.0rc1
3180b9d Code smell: Two space indentation
5432259 Code smell: Avoid needless decorations
8f15707 Code smell: Don't restate results directly after assignment
c3e2353 Code smell: Use &&= for dependent initialization
42a5390 Code smell: Use ||= for conditional initialization
a07bbe2 Code smell: Omit needless checks on defined
07b15bf Code smell: Avoid unneeded blocks
8d1fbe4 Code smell: Avoid explicit returns
889158a Code smell: Booleans are first class values.
81e283b Code smell: Line modifiers are preferred to one-line blocks.
e8cf063 Code smell: Use string interpolation
eefccf2 Code smell: English names for special globals rather than line-noise
184132e Code smell: Use {} for % notation delimiters wherever practical
9ee56f2 Code smell: Inconsistent indentation and related formatting issues
051bd98 Code smell: Miscellaneous oddity removal
77f8599 Code smell: Win32 --> MS_windows
3fbc1d5 Updated GPG rake signing task for new Puppet Labs key
94fa5d5 [#4182] show_diff was broken for streamed file contents
7009704 Fix for #4117 "Storing newly-audited value" messages
9cf9788 Manifests with variables were broken when read from STDIN to puppet apply
835f73c Use the name in the search path for looking for metadata
5bab997 maint:rename resource_type to define in internal dsl
654b564 [#4198] Require 'fileutils' everywhere FileUtils is used
a07af2b [#4196] Move the docs into the source directory structure
3c00591 Fix for #4178 - generalize autoloading to include .rb
cea2e5b [#3582] Remove assumption that Puppet.settings would return values of a consistent type
c58e420 [#4180] Support legacy module structure
b4593f2 Update RDoc parser to reflect change of custom plugin and fact locations
dda165a Fixed #4180 - Updated old module structure to match correct default
1715f3a [#2730] mount ensure present shouldn't unmount
a282cc3 Fixed subscribe example
2353115 Fix for environments in startup script. - Dropped the forced --manifest switch in the suse startup script to allow for environments to re-define this. Otherwise, environments will not work as puppet override configuration with command line arguments.
cfca62b Redmine: 2474 - Fix for mount fstype documentation
3ff38df Fix for #4137 -- Oracle needs text for strings > 255
62dbae5 Fix for #2807 Puppet settings available as variables
a5fc364 [#4161] RDoc fails to parse some of our ruby syntax
b7e2580 [#3169] Adds more debugging to SSL cert verification
70af43f Fix for #4167 -- overriding file permissions in conf file
2c88884 [#4114] Fixes test failures caused by previous 4114 fixes
4a6428b saving work for my unit tests. The redhat one still fails...
1e0d922 [4123] - allows self.instances to correctly report state of services.
8d3ced5 created init provider method self.get_services which accepts an array of filenames to exclude when processing defpath.
cdd4382 [#4114] Fix failures in the unit tests
e419293 [#4114] Added queueing to the log
4b00c6a [#4110] Wrap Type#retrieve calls for backwards compatibility
5f8a242 Fix for #4120 No namevar running puppet doc -r type
6ac36eb [#2370] Allow OpenBSD to add packages with versions and flavors
45a9f37 [#4108] Changed missing Application constant error
a0ea74b [#4149] Don't create two Resource::TypeCollections
7978be5 [#3906] Fixed missing constant Puppet::Rails when using storeconfigs
fb6f2aa [#4136] Specs should listen on localhost
6d4be90 [#3961] Part two: --destroy should also be local
0598f35 Fix for #4148 (2.6 is greater than 0.25.x)
5971898 Fix for #4142 stray use of JSON instead of PSON
74e5bdc [#3172] Fix the arguments to Application::Kick.new, which I had broken
4f06e9e Maint: Explicitly put test sqlite files in a temp directory
84a9412 maint: fix stub failure in report_spec.rb
1f48d68 maint: fix stub failures in report_spec.rb
bee843a maint: fix stubbing in package_spec.rb
528b915 maint: fix stubs in transaction_spec.rb
37277a5 maint: fix stubbing in catalog_spec.rb
ea55e83 Maint: Improve the speed of setting settings.
7c7f6da maint: file_spec heisenbugs
d6d726b Heisenbug: settings as catalog trying to create directories
e579aab maint: spec_helper should reset settings directories on *every* test
298a764 maint: Remove a heisentest that wasn't testing what it claimed
b389392 maint: spec_helper should only get loaded once
3304068 maint: :mutable_defaults to improve spec consistency
08b49c6 [#4090] Fix the run_mode for certs and put tests on the applications to assert their run_mode
e318db6 [#4059] fix the specs to correctly mock the Puppet::Resource.new call signature
ab3d27c [#4059] Minor errors preventing ralsh from running
59bf5e4 [#2713] Enable ELSIF
ebd0311 [#3172] puppet kick can take hostnames as bare arguments
697508d [#4108] Missing constants fail deliberately and with a message
2639a56 [#4092] Changed notify message to defined instead of changed
223157d Fix for #4091 -- require loop in executables
174e02a [#4090] Change how RunMode instances are created so that an object for each RunMode is only created once instead of every time it's called
62e3b61 [#4090] Fix last few tests and renames of mode to run_mode
2a25883 [#4090] Git rid of the idea that run_mode is a configurable option with defaults
75e0662 [#4090] Rename mode (:master, :agent, :user) to run_mode
3cd48d8 [#4089] Replace internal usage of :check with :audit
e848d41 [#3961] puppet cert --generate implies ca_location = :local
255628e [#3961] Rename cert's @mode to @cert_mode to reduce confusion
b2bd05d maint: Confine a test that depends on sqlite
fdc8c35 [#3994-part 3] rename spec tests from *_spec_spec to *_spec.rb
9a94ee2 Fix for test ordering sporadic failure
9ceb454 [#3994-part 2] rename integration tests to *_spec.rb
06dffc1 maint: A test specified that a file wasn't writeable, but was writeable when run as root, which caused the test to fail. Changing the test so that a directory is in place of the writeable file so not even root can write to it.
2baf74e maint: Fixes some noisy specs
0aae5a7 maint: Fixing tests that fail when run as root
0fa10a6 Cleaning up various warnings in specs
2ab123f Removing obsolete nodescope concept
153d7cd Fix #3665 - part 2, node inheritance fixes
dd4fa66 Fix failing tests in spec/unit/resources/type.rb
770a8ea Fix #3665 - main class shouldn't be a subscope of itself
76953d8 maint: Fixes broken order-dependent Tidy specs
9afc67a Fix for pre 1.8.7 compatibility in namvar patch
d62a391 Breaking require-loop
b4af238 Fix for #3985 typo causing warning
9169ef0 Fix: puppet apply trying to use XMLRPC constant
af41beb Remove an old test that had been unintentionally reintroduced by a mistake in a conflict resolution
6a8e6fe Tweak an old test due to new error handling.
5f53bfa Restore error handling for value=
e817ad1 Fix tests broken by level-violation fix
e5478d4 Simplify the newattr method by removing a level violation
4ef40b8 maint: Rework testing of Reports http processor to be self contained
edfcbf9 [#3139] Fixed a problem with the value method for parameters
61e978b [#3139] Fixed a broken integration spec in type tidy
cf9bcad maint: Fixing test to reflect that host environment assignment now takes an object instead of a string
c70c96b Fix some tests broken by changing the call to newattr
a72fb14 Fixing oversensitive test
15004f3 maint: Fix failing test that needed more methods stubbed
60932e1 Fixed require warning documentation
6fcb87d Fixed mcx documentation error
15ae389 Documentation fixes
f95169b [#4006] Fix test failures caused by reverting ticket 2890
b5572ae Bug 3731. Applied Fix suggested by Doug Warner to always flatten out the array
117e6b6 maint: Have 'rake spec' output in color
a7e4fe8 [#3810] Do not create a reports settings block
db44a32 Tweak for fix for #1175 to fix test failures
3bd6f11 maint: Fixing a test typo s/stub/stubs/
ebc3e78 maint: Fixing a failing spec by stubbing a method on a stubbed object that should have been stubbed.
3b4d33c remove tests for removed code
c8089f1 [#2646] Fixes the change to onetime made in b96cd6c
4bf6950 [#3139] Make newattr idempotent
51b70c0 [#3994] rename the specs to have _spec.rb at the end
9958c80 [#4064] Modify the Rails spec to use the block form of confine
af8bd77 [#4064] Modify confine to also allow a message and a block containing the test.
182c003 Fixing #3988 - adding support for watchr
3a44f0e Fix #3932 - Add --charset to puppetdoc for RDoc mode
fb5c1d7 Fix #3907 - Hash couldn't be initialized with an empty hash
9592dd8 Fix #3871 - Add the 'in' operator
3696d95 [#3865] External subcommands
0fc41ae [#3802] Replace rug with zypper
dc1a977 [#3766] Remove YAML fixups
e0e6b64 Provides #3723. Add ability for execs to have several attempts at a successful execution and fix minor bug with logoutput and returns as an array..
c8ca19a [#3674] Make sure that failing to load a feature isn't fatal
2a73b5d [#3674] Part 2: Autoloader load method should propagate failures
7952af5 [#3674] Autoloader should propagate failures
f35c59f Fix #3667 - Fix class namespace
938fbe9 Removing obsolete nodescope concept
49cf2f2 Fixing #3651 failing to pop comment stack for some constructs
0dd4201 Fixing #3072 - Resource generation is recursive
b96cd6c Fixes #2646. Move onetime option from the agent to global defaults so we can specify it in the config file.
0a21e1b [#2522] authorized keys owner is verified
738802e Fixing #2337 - Adding 'freeze_main' setting
50a626d Fixing #1545 - Adding 'caller_module_name' variable
5d1934b Fixing #1545 - module_name is now a variable
bba45f1 [#4055] Confine CouchDB-related specs to the couchdb feature
1c5b67d [#4055] Refactor of abstract Couch terminus, more specs
432db25 [#4055] Add CouchDB terminus for facts
35636e9 [#3921] Fix typo "fact_terminus" -> "facts_terminus"
45ca669 Targeted fix for #3851
c00285c [#3810] Add http reports processor and `reporturl` setting
1d49def [#3804] Fixed one failing spec for RackREST
1e89bff Fixes #3514 - CR/LF line ending in puppet.conf cause silent failure
e6709da [#3409] fix test failures from ldap environment patch
a7884b4 [#3409] environment is not checked when nodes are in ldap
c75b219 Fixes #3395 - CR+LF line endings in manifests cause syntax error
8b127b1 [#3388] Setting host_aliases from [] to [] no longer results in any changes
be7112a Fixing #3139 - all properties can now be audited
986298b Working #3139 - Adding Settings.clear Spec#after
32f6a9d Working #3139 - Removing Property#checkable
58cf8d9 Working #3139 - Catalogs default to host_config
8f3e8bb Working #3139 - ResourceHarness does caching
d6407f4 Working #3139 - removing obsolete checking in Storage
0b95a85 Working #3139 - scheduling moved to resource harness
4627b8f Improving fix for #1175; tightening thread safety
ccc869e Part 2 of fix for #1175 (functions in environments)
7c6b883 [#1621] Composite keys for resources
2396eba Use the 'root' feature rather than directly checking the uid
8128311 fix tests to reflect methods moved from type/file/owner to provider/file/posix
28702a4 variable name error in refactor
19c70b5 Remove over-eager error branch in a complicated If
09881cf Confine out a lib that puppet was failing to load on non-win32
d72fd9d Confine out tests that fail on unix
d1b86ec Behavior change for //UNC_Paths broke an old test
ba506c1 Resolving conflicts with jes5199:ticket/master/2935-settings-mode
f15a324 Fix Exec type
86bd838 Move syslog into a feature
fc92408 Adapt Util::Storage specs and avoid trying to lock on directories
58100ed Relax path qualification check on FileServing::Fileset
1c016a1 Implement quoting on the exec commands and repair specs
6a92894 Avoid trying to symlink() on windows
47c9dd1 Implement "forking" for Windows
c59d864 Avoid non-win32 signals on win32 runtime
bbba9f9 Avoid trying to set uid/gid on windows
a90bcb0 Start extracting the owner managment for files into providers
b51be28 Expand file type to be able to handle Win32 and UNC paths
17a9ad1 Updated version to 2.6.0
a2e809b Fixed RSpec deprecation notice in lexer tests
f054d5b Make specs work on win32
54c4538 Delete tempfiles on win32
97c043f Fix path handling
f80b4c7 Print stacktraces if requested
1d98e67 Adapt defaults to Win32 environment
ea9bb49 More win32? feature def
1645d8e Define posix and win32 features
b3aa3ec Improve error message
d67f60f Fix ProviderDpkg specs to avoid any real executions
e119b04 Avoid setting the timeout before we know which timeout we should set.
d40e6d4 Bug: tidy specs need FileBucket::Dipper
a6b52bb Avoid trying to lock on non-files
533ef68 Removing obsolete FCollection stub from Functions
bc90df6 Functions are added to a module instead of Scope
17e40e7 Slightly restructuring "Functions" file
9d0a38e [#3921] Add facts_terminus setting to Puppet settings
2874729 [#3921] Remove unnecessary require 'puppet/resource'
58a3d27 Fix for #3949 and related
b755f7f Fixed #3912 - Added client certificate name as an internal fact called "clientcert"
b5f14c6 {#3866] Rename the method metaclass to singleton_class to avoid the deprecation warnings from Rails ActiveSupport
2b5bd49 Fixing #3822 - checksums will be loaded from filebuckets
94390de foo
3b7aac5 For #3822 - Reducing checksum code duplication
ca7b166 Fixed unsupported perlstyle regex and few other minor bugs
85f2565 Signed-off-by: Ross West <westr@connection.ca>
a4eb5d5 Signed-off-by: Ross West <westr@connection.ca>
970fd87 Fixing #3791 - client environment is used
cce63d8 Bug #3748 LDAP group membership
4ba3dc2 Fixing #2655 - Adding default parameter values to resources
20a74bc Refactoring tests - replacing stubs with instances
b5db33b Fix for 3664: interpolating qualified variables.
9ddee72 Fix #3664 - qualified variable parsing in string interpolation
a32381e Feature #2935 remove misleading comment
5937af4 Feature #2935 Unify the codepaths for setting settings
b7d387e Feature #2935 Puppet[:mode] and Puppet[:name] are read-only
342298c Bug: Broken codepath in util/settings
6d5566a Feature #2935 settings are in Mode sections instead of executable names
9536723 Feature #2935: method extract require_application
c338fef Feature #2935: Test for if we're "puppet cert"
cbb2802 Code cleanup: remove "self." from setdefaults
37a5530 Feature #2935 Modes: root? predicate
ac7efc8 Feature #2935 Puppet::Mode#master?
5665e39 Feature #2276 Single Executable: Update docstrings
fc29049 feature #2276 Single Executable: use new names for settings sections
631552c Feature #2935: Applications should declare modes
8f4d644 Feature #2935: lazify require graph for applications
6b26a7c Feature #2935: Puppet::Mode
b65d1af Feature #2276 Single Executable: usage message
76304f8 feature #2276 Single Executable: move CommandLine methods
e9627a0 Fixing #2658 - adding backward compatibility for 0.24
61a719f Adding #2658 - Adding support for run stages
d13f8ac Fixing #3671 - --compile Catalogs are pretty-printed
89e8745 Fixing #2655 - Adding default parameter values to resources
edcf429 Refactoring tests - replacing stubs with instances
3dfb762 Fixing Catalog conversion
0d4fd60 Fixing #1903 - metaparam inheritance is much faster
047ebfe Fixing Parser::Resource param validation
2fae0bd Fixes #1999 - Allows the 'apt' provider to downgrade packages.
b10d35d Fixes #3745 Catch unhandled exception in ssh_authorized_key provider
584961a Fixed #3721 - Removed -u option from crontab on HP-UX
a15a70c Fixing tests broken by conceptual merge conflicts
5988f76 Fixes #3663 - It should be possible to list signed hosts only
2c153b1 Fixing #448 - relationships have their own syntax
052f98f Fix #3408 - enable puppetd http compression
3eaf69c Fix for conflict between fileserving streams and none-checksums
2cf7222 Fix #3373 - Client side file streaming
ee5d7f1 Add master side file content streaming
63c122f Fixing tests broken by Luke's CRL flag patch.
91e6022 Fixes incorrect line in partial CRL fix
379bda0 WIP - trying to fix #3460
3947574 Updated Template documentation link
5fd6e54 Change the main spec to an apply spec
009629f Feature #2276 Single Executable: usage message
5b64d3b feature #2276 Single Executable: optparser should get CommandLine#args instead of ARGV
5683fd9 Feature #2276 Single Executable: Pass a commandline object to the application
d038a1d Refactor #3706 Reify eigenclasses of Applications
7656ba7 feature #2276 Single Executable: CommandLine can be instantiated
63e2e56 feature #2276 Single Executable: subcommand method
b6e2ce6 feature #2276 Single Executable: help info
b073722 feature #2276 Single Executable: help for apply
bfad735 feature #2276 Single Executable: rdoc paths on ubuntu
7103378 feature #2276 Single Executable: legacy settings
54c1cc5 feature #2276 Single Executable: "puppet describe"
c79b228 feature #2276 Single Executable: "puppet kick"
6bdda8c feature #2276 Single Executable: "puppet cert"
f9783fc feature #2276 Single Executable: "puppet master"
1d8bd0d Fix #3552 single executable should display usage
722a27f Fixes #3702: the 'log' report now sends the host name as the log source again.
ddd40bb Fix for #3690 failing to calculate error codes
d61a69a Fixing #3668 - fixed autoloading classes from modules
f66095d Fix #3656 JSON serialization of dependencies
f0a0084 Fixes #3582 - Adds dbport configuration option for specifying database port
8b99367 Adding indirector support to Resource Types
748aed9 Fix #3552 single executable should display usage
eafde5c Added support for flat packages in the pkgdmg package provider. Added a test in: ./spec/unit/provider/package/pkgdmg.rb
c9e3d75 Fix: the rcvar name is not necessarily the same as the service name. (More and more I get the feeling that FreeBSD's rc system is totally unsuitable for Puppet. What about porting Upstart or SMF to FreeBSD ... ?)
861c177 Added proper status command
5f72eb9 Re-included old BSD service provider, made new one default for FreeBSD
c3cd24b Rewrote FreeBSD service provider
1250f80 Fixed documentation issues exposed in #3772
211782f Updated CHANGELOG for 0.25.5rc3
7c59acf Renamed all references to Reductive Labs to Puppet Labs
e82f5de Fix for #3107 Changing users on AIX
44f1465 Fixing #2864 Added support for AIX System Resource Controller (SRC) - service start stop
02ed8db Fixes #2836. Add hold support to dpkg provider
0f2d3ce Fixes #1223 Add Zypper support for SuSE machines
a166d50 Fix for #3399 zone type should handle exclusive IP stacks
af521fa Adding #3518 - basic dot format support
9b2b0ec Fix #3551 rake spec fails to run integration specs
6a66d5e Update Red Hat spec file for 0.25.5
46c72bb Updated CHANGELOG for 0.25.5rc2
ee0cc07 Fixing #3533 - Removing all transaction cleanup
11189fb Fix for #2910 -- Tidy/matches is too tricky to use
913b63c Bug #3451: Don't leak the terminus class setting from Puppet::Resource::Catalog's spec
a228399 Fix to the fix for #3295
ae52005 Write ssh_authorized_keys as user
8c5e80e Fixing bad test
088c801 Fix for #3558 -- source file reading speedup
cd06b87 Fix for #3556 Plussignment value melding
2de7da4 Fixed #3655 - Puppet doesn't find installed packages with portage provider
d20d5de Fixed #3672 - Error message on duplicate fileserver mounts incorrect
6ae6821 conf/redhat: Add notifempty to logrotate config
7fc66d5 Fixed stored configuration documentation
14456b4 Fixes #3653 - Changed default factpath value to better reflect plugins in modules
f3e466b Partial fix to #2837 - changed warning message to debug
686239f Fix #3555 - fix state of purged lists
6f8a1e9 Updated Rake tasks to no longer load puppet.rb
83a8c68 Fix #3540 - name methods correctly
3d395e8 Fixes #3295 - generate() now sets the working directory to the directory containing the specified command.
0f077c7 Added YARD task
b49c60b Update man pages and partial doc fix to #3491
115f37d Fixed #3532 - Typo in lib/puppet/ssl/host.rb
784dd26 Updated version and CHANGELOG to 0.25.5rc1
4a6474c Modify SuSE spec file for 0.25.x and correct shebang lines for puppetd/puppetmasterd
385506f Fixes #3460 - Makes Puppet FHS compliant by moving /var/puppet to /var/lib/puppet
b494427 Fix for #3101 (bug in MRI 1.8.7)
966b269 Fixes #3419. OS X 10.6 Ruby doesn't set supplementary groups
49be54e Revert the guts of #2890
e69b7db Fail gracefully on packages that don't have the HOMEPAGE variable set (e.g. dev-lang/php).
83ac6b8 Fixed #3443 - Typo in mount type
dfe5c3a Fixes #3135 - darwin doesn't support 'mount -o remount'
2a60e1e Adding :catalog_terminus setting
626945b fixing obsolete comment in puppetd
9fbb69f Adding support for only using cached catalogs
7e1e76e Refactoring Configurer to enable the next feature
b28e21a Fixed changelog Rake task
e93eab8 Fix #3155 - prevent error when using two matching regex in cascade
b883272 Fixed puppetlast typo
67bf142 Fixed README contents to reflect Puppet Labs and docs and wiki changes
e35e142 Fixed link typo
d40e24c Fixed #3384 - Updated broken link
da00f68 Making a Puppet::Module test more resilient
9792915 Fixing yumrepo type to use 'flush'
9ee4c2d Only trying to retrieve passwords on OS X when root
8c31ebe Removing obsolete tests
aee9c29 Fixing a warning in the aix package provider
232ad8f Removing tests for code that was removed in the REST refactor
94fddbc Fixing and porting Transaction Report tests
13d141a Fixing Property#change_to_s in rare case failures
66858ef Fix test in parser.rb due to API change
0f254be Fixing Hash functionality with non-constant keys
41aeba4 Removing vistigial method in ASTHash
1821187 Porting/removing group test/unit tests
03532e0 Porting a simple set of tests from test/unit
006e6af Removing obsolete test
1a6e08f Fixing Transaction integration test
410b71c Removing invalid File integration test
effa719 Cleaning up content/source code
456447c Protecting spec_helper chmod from failure
fa64774 Redeleting puppetmasterd integration test
797f412 Making SshAuthorizedKeys tests less brittle
622bb70 Markus's patch concerning string interpolation
23adec5 Fix tests that use or stub find_by_checksum, which I just changed the signature of.
4ac8e2c The pure-ruby YAML lib doesn't accept parameters
e31fe8c Fix a failure in new FileBucket where it was impossible to read from a bucket with a non-default path.
3797c7a Update YAML dir test to match behavior
83d8bda Fix heisenbug in spec/unit/provider/mount/parsed.rb
dde69c3 Remove test for old RDoc work-around
c5ce824 Fixing various broken Resource::Type tests
6cd6c47 Renaming and fixing puppetrun tests.
a27013a Fixing calls to "class_scope" in Scope tests
84d6892 Fixing all 'require' function tests
b643413 Removing any mentions of :casesensitive setting
fe140a2 Migrating "puppet" executable integration test
edef647 Fixing 'puppet' to directly run manifests
fff8d04 Fixing syntax warning
7c25317 Moving puppet back to bin
a4d1ba0 Puppet::Parser::AST::Leaf#evaluate_match "insensitive" renamed to "sensitive"
404bdfa Repair validate_checksum codepath, even though it is disabled.
e895494 Puppet::Parser::Resource.new parameters have changed
94651df Add stub to Puppet::Parser::Collector test to prevent runaway stub failures
40c1fb0 Resolving conflicts with ???
1059370 Fixing a typo from a regex
3eeebf5 Fixing change printing for content/ensure
47c3ca1 Converted File[checksum] to a parameter not property
44cba9c Adding "checksum?" helper method to Checksums module
d05d25c Refactoring File[source] tests somewhat
aab2374 Resolving conflicts with luke:tickets/testing/2954
86cf226 Adding virtual and exported resource support to the DSL
9d5ba41 Cleaning up ResourceAPI tests
9060766 s/DSL::ResourceHelper/DSL::ResourceAPI/g
6d2a10b Adding simplistic pure ruby interface
e515513 Adding environment support to parser resources
30f49bb Resolving conflicts with ???
b7015d7 Moving the string interpolation parsing to the parser/lexer
07cfdd0 Resolving conflicts with jesse:feature/master/3394
ad148d6 Resolving conflicts with luke:tickets/master/2759
922cf1a Resolving conflicts with ???
0d70468 Finishing renaming :params to :parameters internally
ad93d0e Forcing parent evaluation in resource types
6e4db82 Fixing type/title resource resolution
aa659f2 Converging the Resource classes further
5401a7c Adding strictness checking to resources
9c867e6 Fixing most of the broken tests in test/
274d1c5 Adding tmpfile cleanup to tests
7089446 Removing Resource::Reference classes
4871c90 Adding support for class parameters
4709e9b Removing :paramcheck and :typecheck settings
744295d Allowing Environment.new to take an environment
4f907c6 TypeCollection now supports namespace arrays
2fa0a48 Adding parameter validation to Puppet::Resource
aff5992 Fixing failing Environment unit tests
61636e4 Tuning file load order
7a99a1d Removing obsolete Settings comments and require
af9a920 Adding an environment helper
c8e89cc Changing the interface of Puppet::Resource
b7ea180 Partially fixing #2954 - Adding class parameters
cbe2c49 Fixing test structure
4bff506 Indirector/FileBucketFile warnings
0917248 REST: Fix a state leak causing test failures
8f9fc30 REST FileBucket: REST barfs on relative paths
23ccefe REST: hide Request object
d8e1b27 Feature #3394 REST runner, execution
1603f73 Feature #3394 REST Runner, preparation
16658a0 Feature #3383 Part 2: Remove RAL XMLRPC
eda649b Feature #3383 RAL over REST
09b1412 Fix tests on #3347
e5a7800 Feature #3347 REST-ified FileBucket
f838389 Fix a failing test in #3115
9acd0b2 Feature #3115 REST-ified status()
b581c23 Fix #3229 - use original value in case/selector regex matching
490a03d Cleaning up a test.
576accd Removing unused Checksum::File terminus
58920a0 Converting File terminus to use formats.
37fd6ae Fixing datadir defaults to match new standards
bf3359e Adding client and server data dirs
b41d535 Adding filename extension support to formats.
7504f1e Resolving conflicts with ???
d0389f4 Renaming Parser::ResourceType to Resource::Type
67ef78d Removing Interpreter class
b82b4ef All non-transient parser references are gone
644ad7e Fixing callers to Parser to only pass environment
9f8e0c0 Using the RTC helper to find the known resource types
1705366 Always warning if autoloading a file fails
7bef2e0 Adding helper module for finding known resource types
804105d Moving Rails initialization to Compiler terminus
26b272b Parser now uses Environment resource type collection
cb16908 Adding 'known_resource_types' to Environment
201889b Renaming LoadedCode to ResourceTypeCollection
2c2b3c2 Storing per-environment LoadedCode instances
6bf1953 Removing old, never-used DSL code
df2d392 Adding support for parsing ruby files
b938edf Fixing test structure
847233f Adding []/[]= support to Parser::Resource
6e04fba Fix for #3366 - --tags '' treated as boolean 'true'
33b565a Fix for #3424 and tests to prove it.
4820a1b Fix for #2604 Pure Ruby yaml generation
1c5b3d7 Fixes #3113 - When importing a manifest puppet needs to chill
e6a720b Fix for #3412 install.rb should not put "." first in the tmp_dirs
b1b3bcf Resolving conflicts with testing
ba2a3af Fix 2239 (step five): introduce new Puppet::Transaction#stop_processing? flag and associated check thereof within the resource evaluation code. This should allow for the transaction to bail out of its processing if it finds that a stop has been requested, based on the state of Puppet::Application.stop_requested?.
9cb6841 Fix 2239 (step four): Refactored Puppet::Daemon's stop/restart methods to set status flags appropriately in Puppet::Application, and removed call to now-deprecated @agent.configure_delayed_restart. This should get the restart and stop behavior for daemons and their agents working nicely with the new global process status interface of Puppet::Application.
82f852a Fix 2239 (step three): Refactored Puppet::Agent to base starting/restarting behaviors and predicates on new run-status interface of Puppet::Application.
edbe9b6 Fix 2239 (step two): introduce Puppet::Application.controlled_run method to provide simple status-restricted execution of a passed in block; this can replace the process status checks and properly handle delayed restart behavior for Puppet::Agent.
2cf647c Fix 2239 (step one): introduce global settings represeting application run state with methods for setting the state and appropriately-named predicates for querying state, all in the Puppet::Application class itself. To be used by Puppet::Daemon and Puppet::Agent and Puppet::Transaction for better response to TERM, INT, HUP.
ce944a5 Fix unit tests in file/target.rb
481ddb8 Name change of event in ral/type/exec.rb
1ebc91e Use a helper function to evaluate a resource since the API has changed
bfb1fa5 Allow skipped resources to process events
a18b05d Actually invoke the allow_changes? method in ResourceHarness
bf2f088 Generated resources' events are actually bound to the resource that generated them.
50ed75b Remove test that tests internal class structures which have changed.
1779079 Remove stale set_trigger
9154aca Since the types stored in resource's @parameters have changed, we need to also change include? method to be more robust.
2a2ab75 Fix test failures due to name changes of event symbols
0a72a98 Remove rollback test, since rollback was removed.
010907b Mark resource/status as failed if they are associated with a failing event.
17bccb0 Restore noop non-behaviours
8465cd0 Resolving conflicts with reinh:feature/master/single_executable
0f768ed Removing now-obsolete user tests
7627441 Fixing most failing test/ tests.
9d9b20f Fixing Configurer interface to transaction report
eb0a4b5 Fixing fingerprint tests to work with new log validation
f4ef039 Changing REST report integration test to use new interface
fdefb64 Fixing "require" function to use new class interface
266bc08 Removing now-obsolete "retrieve" method on package type
67a75db Fixing broken selinux tests
2777e1f Fixing feature validation when passed one item
5aa26d0 Changing method profile for other event queueing
ec7ea27 Refactoring event queueing for performance
68ce086 Changing the method profile of EventManager#queue_event
9919b14 Moving Metric management to the reports
a9fc134 Removing mention of @changes in Transaction
a18769d Cleaning up the report tests a bit
386b3e5 Fixing #2759 - reports now have complete change info
fbd5b0a ResourceHarness now doesn't check params with no 'should'
3f6c948 Changing Transaction to use the new ResourceHarness
6051599 Fixing log message when changes fail
149d5ef Fixing some compatibility and old tests
c30494f Renaming some methods in Transaction::Change
8d5f052 Adding Transaction::ResourceHarness class
6651aa4 Adding first version of Resource::Status class
4bb35a7 Fixing File type indentation
796d882 Removing last event collection transaction code
e838bcc Solidifying the RAL/Event integration.
977595b Refactoring the Change/Event/Property interface
5776fe4 Cleaning up the Log initialization code.
2292b76 Refactoring the RAL interface to logging
d93d80a Using Logging module in main Puppet module
c6dd180 Adding tests for "Logging" module
242209d Correcting comments and making report timestamp internal
a4b77f6 Failing in app/puppet if facts are not found
f925475 Fixing file content logs
73f57f2 removing extraneous comment
4be8601 Adding Transaction events to Transaction reports
2aa579b Removing a redundant method in Report
5a8b460 Removing unused code and adding a couple of tests
9a78bee Adding tests for the 'report' log destination
f2ed655 Extracting event management into a separate class
329527f Changing SimpleGraph.matching_edges to expect one event
f8d7c44 Moving event creation to the resource
ee9cff9 Reorganizing Property class to match current style
4212f1c Cleaning up Event creation
8280987 Adding "type" instance method to enhance Demeterness
ad90900 Random code cleanup
32d34e9 Moving Ensure property into separate file
3c86666 Moving Parameter utility classes into separate files
2cbd9e8 Switching transactions to callback-based events
6a450c5 removing never-used code
379ac8f Moving log destination code into separate files
b2d1728 fixed a couple of typos
7ab29c4 Unit tests for path changes
a8245d8 Handle path elements with ticks and spaces
98581ad Fix builtins glob in single executable
b4b07f5 Fix failing specs
e7bc19a Rename puppet application spec to main
c014c29 Renaming the old puppet executable
deff92d Find both bin and sbin usage docs, fail gracefully
3c8d012 Fix application name in bin/ralsh
be0ecf8 Initial puppet single executable
7a32777 Renaming applications, mostly removing 'puppet'
b19a044 Some tests were leaking state when the test failed
5b2802c Typo in method call in test.
6a148e2 Supressing warnings (not really failures) in test/unit
06deee7 Fix test using wrong Puppet util filesetting group
74f5167 Mock user in SUIDManager tests
000d37a Removing resources generate tests
11379c0 Removing old test for service/debian provider
2b8125c Replace test/unit file write test with spec
164f1ce Allow adding single key to hashes
fd427a5 Raise an error when appending not a hash to a hash
75c32f9 Fix #2389 - Enhance Puppet DSL with Hashes
9122ac5 Fix #2929 - Allow checksum to be "none"
73c8d0d Fix #3186 - require function set relationship only on the last class
c5a4de2 Fixing #3185 Rakefile is loading puppet.rb twice
c694c4d Fix #3150 - require function doesn't like ::class syntax
075f3c8 Added time module to tagmail report
dfb8082 Fixed the return types were valid, and removed the copy paste error with the exception logic
6e16ea1 Resolving conflicts with ???
bca7e2c Add AIX package management support (installp&nim)
b2c9455 Fixing #3148 Settings#without_noop when run with no noop setting
8bafc37 Move scope parenting & class_scope from Compiler to Scope
7403c6e [#3392] Better Rakefile, remove puppetmasterd spec
de94f68 Fixing tests in pkg provider
4b55fb0 bug #3407 Part 2
f891ba2 Fixing #3407 Failing tests in spec/unit/node/environment.rb
af9c19a Bug #3406 augeas spec fails if there is not a default provider
718a87a Bug #3402 Stub returning invalid type for :noop
88d6cd5 Bug #3401 Spec failed due to missing manditory setting in mock
d9920bc Bug #3400 Bad mocks causing failing tests
c6f02f2 Fix #3167 Duplicate constant warnings in dpkg.rb
70c71c5 Fixed Rails database tests
46f9d00 Fix #3117 - cert fingerprinting uses a method not available in ruby <= 1.8.6
04842ef Fixed test error message.
fcce222 First shot at the OpenSolaris pkg(5) provider
3e9677f Feature #2839 - fingerprint certificate
91c44b4 Fix a few puppetd specs tests
d77c9ac Revert "Feature #2839 - fingerprint certificate"
58a81ba Fixing #1054 - transaction reports are always sent
282b4b3 Removing some unneeded validation code from Transaction.new
66a3e6a Removing unused configurer code
2044550 Fix #2894 - exclude .pp files under modules files directories
d31ff7e Adapt to method name change since 8971d8
a9fb82b Feature #2839 - fingerprint certificate
a967b93 Feature #2395 - revoke when cleaning a certificate with puppetca
e26e831 Updated test series
53869e9 Fix #2818 - scope variable assigned with undef are not "undef"
4226e01 Fix for #2959 (calling exit status on a nil report)
8971d8b Fixing #2596 - Node, Class, Definition are not AST
39d4a93 Adding a context method to the Errors module
22c642d Extracting language doc support into a module
adc211a Adding module metadata
bf40f4f Upgrading rspec for tests to 1.2.9
61d1911 Fix 2841 - Puppetdoc/RDoc parses realize function
e63d23e Added tickets/master/2596 to the testing branch
41da962 Feature 2827 Option to disable managing internal files
c9f40be Fixed #2568 - Add database option 'dbconnections'
2d137e2 Fixing #1507 - Adding a :ca_name setting
089ac3e Fixing #2617 - using the searched-for REST name
28e1bc6 Always using the CA_name constant instead of "ca"
2d4b795 Fix #1934 - detailed-exitcodes for puppetd
0f61816 Fix #2649 Allow ssl dir creation in --noop mode
53be6f8 Fix #2796 - Fix puppetdoc rdoc selector parsing
391786f Fix #2795 - puppetdoc rdoc reports a better error message
b832d81 Fix #2784 - puppetdoc/rdoc didn't parse mono-instruction class content
b1deb89 Covers the RDoc Puppet Parser with specs
ced5a78 Fix #2376 - Display class/node inheritance in puppetdoc
8d9fbbd Fix #2703 - add 'require' to puppetdoc
41b7c3c Adding an example yaml node script
66a44dd type augeas: add 'incl' and 'lens' parameters
c61335f Patch to address feature #2571 to add Oracle support to Puppet
0.25.5
======
d71bd68 Updated CHANGELOG for 0.25.5
d88b357 Fixes incorrect line in partial CRL fix
dec84e5 Fixed documentation issues exposed in #3772
0.25.5rc3
=========
4daf8c3 Updated CHANGELOG for 0.25.5rc3
9214400 WIP - trying to fix #3460
9d3e98b Minimal footprint fix for #3751 (serialization 0.25.5 <-> 0.24.8)
d481340 Updated Template documentation link
5a1a45c Update Red Hat spec file for 0.25.5
0.25.5rc2
=========
2257605 Updated CHANGELOG for 0.25.5rc2
5258a0a Fixing #3533 - Removing all transaction cleanup
bcde541 Fix for #2910 -- Tidy/matches is too tricky to use
5abe571 Bug #3451: Don't leak the terminus class setting from Puppet::Resource::Catalog's spec
ebd924c Fix to the fix for #3295
ce233aa Write ssh_authorized_keys as user
6739bab Fix for #3558 -- source file reading speedup
b0e3c61 Fix for #3556 Plussignment value melding
8a30495 Fixed #3655 - Puppet doesn't find installed packages with portage provider
e4130af Fixed #3672 - Error message on duplicate fileserver mounts incorrect
1275a47 conf/redhat: Add notifempty to logrotate config
134204d Fixed stored configuration documentation
1aa98a6 Fixes #3653 - Changed default factpath value to better reflect plugins in modules
44f6d64 Partial fix to #2837 - changed warning message to debug
3a1b178 Fix #3555 - fix state of purged lists
f6046ab Fix for #3577 -- to_yaml parameter in 0.25.5rc1
f351e2d Renamed all references to Reductive Labs to Puppet Labs
cf7e696 Updated Rake tasks to no longer load puppet.rb
b93924e Fix #3540 - name methods correctly
9bc2f28 Fixes #3295 - generate() now sets the working directory to the directory containing the specified command.
3ee6834 Added YARD task
99818ef Update man pages and partial doc fix to #3491
f988af3 Fixed #3532 - Typo in lib/puppet/ssl/host.rb
f0e12e5 Fix #3496 - suppress transaction debug message
0.25.5rc1
=========
0eea2f5 Updated version and CHANGELOG to 0.25.5rc1
57ae381 Modify SuSE spec file for 0.25.x and correct shebang lines for puppetd/puppetmasterd
d90ec79 Fixes #3460 - Makes Puppet FHS compliant by moving /var/puppet to /var/lib/puppet
ae0b0bf Fix for #3101 (bug in MRI 1.8.7)
9db066b Fixes #3419. OS X 10.6 Ruby doesn't set supplementary groups
306d082 Revert the guts of #2890
4eea77a Fail gracefully on packages that don't have the HOMEPAGE variable set (e.g. dev-lang/php).
f5b8494 Fixed #3443 - Typo in mount type
b0ef2c6 Fixes #3135 - darwin doesn't support 'mount -o remount'
7018cf5 Adding :catalog_terminus setting
978ab8a fixing obsolete comment in puppetd
6d13d0d Adding support for only using cached catalogs
bc28715 Refactoring Configurer to enable the next feature
ba43d7b Fix for #3366 - --tags '' treated as boolean 'true'
5ab5e8a Supressing warnings (not really failures) in test/unit
e4df0b0 Fix test using wrong Puppet util filesetting group
eeb3d74 Mock user in SUIDManager tests
9ea27db Removing resources generate tests
218e3e9 Removing old test for service/debian provider
1556938 Replace test/unit file write test with spec
2defc00 Fix for #3424 and tests to prove it.
44798b9 Fixed changelog Rake task
5d10f65 Fix #3155 - prevent error when using two matching regex in cascade
fbedb99 Fixing #3148 Settings#without_noop when run with no noop setting
389c77b Another trivial follow-up fix for #2604: invalid path to zaml.rb
56b5753 Fix inefficient SimpleGraph#matching_edge
4b2b9eb Fix #3229 - use original value in case/selector regex matching
19863c0 Fix #2929 - Allow checksum to be "none"
fd76142 Fixed puppetlast typo
3b4e782 Follow up for #2604, debug msg left behind.
e44430b Fix for #2604 Pure Ruby yaml generation
74cd55f Fixes #3113 - When importing a manifest puppet needs to chill
7ec50a7 Fixes #3387 - Handle path elements with ticks and spaces
d561a98 Fix for #3412 install.rb should not put "." first in the tmp_dirs
751df45 Fix #3186 - require function set relationship only on the last class
a1d216c Fixed the return types were valid, and removed the copy paste error with the exception logic
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
71653a7 Fixed #3162 - tidy does not remove empty files when "size => 0" is set
efd0f76 Fixed #3128 - Updated man pages and moved puppet.conf.8 to puppet.conf.5
ad4f94a Add version number to puppetlast display.
0533cea Forgot fakedata called in spec
6416f91 Fixing #2669 puppetmasterd integration has leaky state
8a3a205 Fix for #2327, check the return types from augeas and fail where appropriate
2ae7516 2047: Add a not_include into match
55f6239 Minor unit test fixes
b7b7a1c vim: Improve function matching when functions contain ')'
b3c363c vim: puppetDefArguments is contained by puppetDefine
f9e05a8 Fix for #3094 (libdir should take ":" delimited path)
b473264 Fix #1842 Net::HTTP#enable_post_connection_check doesn't work anymore
9419c2b Fix for #3035 (redhat services use init for source)
10becce Fix for #3077 (unit tests broken in 0.25.1-->0.25.4)
49a7185 Fix for #3085 (user_role_add pulls from same source as useradd)
1f086c2 Fix for #3114 (ruby's arbitrary limit on process groups too low)
0.25.4
======
c5eef04 Updated CHANGELOG for 0.25.4
0025e13 Partial reversion of patch for #3088 to fix #3104 (Exception misreported)
bfc9e45 Updated CHANGELOG for 0.25.4rc3
0.25.4rc3
=========
a91c476 Fix for #3088 (catching Exception also traps SystemExit)
1a263e2 Fix for #3089 (timestamp may now be a time object, not a string)
75634b7 Fix for #3093 (also need to be able to call pkgget_with_cat on class)
94e269c Uncommeniting the fix for #3001
9636b93 Updated CHANGELOG for 0.24.5rc2
0.25.4rc2
=========
d4319a5 Minimal fix for #3001 (failing to fetch metadata on dangling symlink)
cdcbdc7 Fixing #2914 - pre/post hooks now work for transactions
67216aa Fix for #3075 (sshkey host_aliases ignored)
e4462c0 Updated version and CHANGELOG for 0.25.4
0.25.4rc1
=========
441879f Revert "Fix #2845 Cron entries using "special" parameter lose their title when changed"
f7e1435 Updated rake task to fix gem build issue
49013f0 Updated version and CHANGELOG for 0.25.3
0.25.3
======
f8c1b08 Reversion of pipe IO patch for testing on #3025
7f25805 Fix #1464 Mount complains about missing fields
c99f394 Fix #2845 Cron entries using "special" parameter lose their title when changed
0a7e212 Fix #2887 'service' tests paths too early
dd22b71 Replaced ugly gem creation task with slightly less ugly task
d0efcc6 Added tasks directory to Rakefile and gem task file lists
8a6d66e Added puppetpackages task description
eada68a Updated CHANGELOG for 0.25.2
0.25.2
======
6111ba8 Fix for temporary file security whole
e7d98cc Fix for #2999 (absent package handling on solaris)
87136b4 Fix typo in documentation: wheter vs. whether.
cbc2ef0 Partial rollback of refinements to fix for #2994
fd631b9 Do not close stdout or stderr in execute.
f878fe8 Update Red Hat spec file for 0.25.2
4394c48 Updated CHANGELOG for 0.25.2rc3
0.25.2rc3
=========
13cbf04 ReFix 2675 ending slash in directory should get stripped off
5c6f07b Use a pipe instead of a temp file for command output.
7e64393 Additional fix for #2994 (followed symlinks do not have checksums)
7e2e12b Fix for #2995 (don't fail to load PSON when UTF-8 missing)
c84186a Revert "Fix for #2731 (problem communicating with processes in SELinux)"
74d9693 Updated man pages for 0.25.2
7e2b1e9 Fix for #2995 (don't fail to load PSON when UTF-8 missing)
d1ff4b3 Fix for #2994 (undefined method "_file" message)
4d81511 fix #2987 - check correct hash entry
0.25.2rc2
=========
682000b Updated CHANGELOG for 0.25.2rc2
e4bb529 Fix for #2967 (RFC-1123 problem and regression on wildcarded domains)
776be7c Updated CHANGELOG
0.25.2rc1
=========
a73f799 Updated version
26e7486 Fixing failing tests
05e897e Fix for #2881 (ralsh doesn't find individual parsed resources)
e04f9e4 Code smell reductions
24654a2 Making provider/host/parser.rb compatible with host_aliases
49530ad Fixing #2964 updated resources cannot be collected until they are exported twice
6ab2453 Fix for #2731 (problem communicating with processes in SELinux)
0e5d264 Fix for #2940 (propogating nil rather than reporting the error)
d60ea0e A slide down the RFC-1123 slope towards MS Windows compatibility and chaos
b185801 Fixing #2960 Test Failed: 'Puppet::Type::Mount::ProviderParsed when modifying the filesystem tab should write the mount to disk when :flush is called
5e5c8b5 Fixing tests
0cb5e7d Fix for #2943 (Make puppet --apply respect --preferred_serialization_format)
0884035 Fix #2970 spec/unit/provider/ssh_authorized_key/parsed.rb has order dependencies
b86decc Fix #2816 MySQL server has gone away
854c065 Fix for #2813 (alias propety v. alias metapram)
813cb58 Fix for #2765 (--no-fqdn regression in puppetrun)
e9a0cb7 Fix for #2657 (retain old setting if config has syntax error)
727ee72 Fix #2966 spec/unit/util/queue.rb can't be run twice
8c8e921 Fixing #2963 spec/unit/util/autoload.rb depends on global state
ea90daa Fix for #2965 (Chatty SELinux message)
fc221ff Fixed RSpec deprecation error
037b99a Fixing #2958 inconsistent errors in spec/integration/bin/puppetmasterd.rb
d11c750 Fix for #2951 (SELinux test errors on OS X)
0dc2dba Fix for #2890 (the cached certificates that would not die)
03f37ac Fix for #2950 (parens needed warning)
61fd460 Fix #2924 Test Failed: Puppet::Indirector::FileContent::FileServer when finding files should find plugin file content in the environment specified in the request
2432b23 Fixed test typo
f5960ce Closed #2937 - Migrated a number of requires to features
2d88926 Fix for #2869 (SELinux tests failing under some load orderings)
18c5165 Adds partial IPv6 support to authstore
857047d Fix for #2567 (Authstore does unintended/pointless DNS lookups)
dddbd28 Enabling steps for #2567 (Authstore does unintended/pointless DNS lookups)
ea0a43f Fix 2948 Failing rests in spec/unit/rails.rb
b6f4291 Fix #2923 failing tests in spec/unit/ssl/host.rb
bf7c108 Fix #2677 Proper OIDs on puppet.schema for LDAP
e0488b2 Fix #2808 puppetqd doesn't give an error when no config is given
7b2e2ba Fixing 2851 spec/unit/network/rest_authconfig.rb test descriptions change
1c69af2 Fixing 2855 Inadvertent zlib dependency
3528a7b 2850 spec/unit/application/puppetd.rb generates warnings if run with certain other tests
d343af0 2876 spec/unit/indirector/catalog/compiler.rb changes behaviour
a7fae47 Fix 2936 Insufficient mocks for webrick in spec/unit/network/http/webrick.rb
b96b757 Fix for #887 (safely setting pager to cat for blastwave)
d685f44 2633 file and line info on bad params in type/file
4326eb2 Fix for #2817 (links created even when links property set to follow)
118adc1 2875 spurious test failure in spec/integration/file_serving/content.rb
0f63a54 2877 race condition in webrick
4895329 Fix for #2921 (test not checking for what it really wanted)
f47fa40 Fix for #2925 (accept higher versions of rspec)
c261721 Fix for #2911 (Allow capital letters in selinux contexts)
bf7d650 Fix for #2900 (rug output parsing too specific)
cccbca4 Fix for #2786 (failed trying to backup directory in recursive purge)
6dfac97 Fixing 2907 rspec crash when spec/unit/application/puppetrun.rb is run after spec/unit/util/ldap/connection.rb
1c8d272 Fixing 2870 Spurious failures in spec/integration/ssl/certificate_request.rb
979440f Fixing 2862 spec/integration/file_serving/metadata.rb fails unless run with other tests
e04d299 Fixing 2858 spec/unit/application/puppetmasterd.rb fails if run twice
53a9805 Minimal fix for #2822
9ac1ed6 Fix for #2863 (calling each on uninitialized tag list)
bd9e06f Feature 2827 Option to disable managing internal files
8b66998 Fixing 2849 puppet changes sshkey alias every run if it is blank
7136c85 Fixed spellquote function documentation
de16fd3 Updated yumrepo type documentation
d1fa7cf Fixed --no-ca option in Gentoo also
8b5b4b6 Fixed incorrect command line in Red Hat sysconfig file
623d9c7 Fixing 2886: Failing specs in format_handler
feb021f Avoiding rspec bug which causes 'be_all' tests to always pass
228f105 Removed some extraneous files from ext
01c98f6 Fixed #2798 - Correct issue with crontab provider on AIX
f7c5ceb Fixing 2725 Error message when permissions incorrect on file server directory
07b94b4 2842 Format debugging should be removed
3abcc89 Fix #2783, take2 - puppetdoc should use environment to get modulepath/manifestdir
f5dd6c8 Fix #2831 - puppetdoc doesn't cope with regex node
4a06379 Fixing #2857 (quote nesting error)
9a41c35 Fixing #2791 fs_find should follow symlinks
5629092 Added additional documentation to file mode attribute.
dc8812c Fixing 2792 selinux tries to set properties on unsupported filesystes
57632a0 fix #2854 - parse timestamps
cb6bc27 fix regex for non-installed packages
9cfe390 Fixing 2812 authorized_keys without comments fail
53b3b86 Fix for ticket #2844 (file recursion generated vs. explicit prefix)
8129caa Fix for ticket #2700 -- check for @explicit_waitforcert in puppetd --test
e32f980 Fixed #1806 - supplementary groups are not reset
be7ff82 Fix 2768 maillist resource is broken
48beaba simplify and fix portage provider
0ac0ce9 Implement tasks for git-based workflow.
bd5dc64 Possible workaround for #2824 (MRI GC bug)
c1e47a4 Fixing #2789 puppetrun fails without --tag
106c9a9 Fixing 904 RDoc::usage incompatible with rubygems
5ed2e26 rack: SSL Env vars can only be in Request.env
7f2e5fc Fix #2671, preferred_serialization_format does not complain about invalid values
f0eaf20 Fixing #2764 ActiveRecord 2.1 support
eaab789 Fix failing tests introduced by #2797
55d8ffa Fix #2810 - adapt tidy to new FileSet api
236bacc conf/redhat: Prevent killproc from removing /usr/sbin/puppetmasterd
41f025c Fixed ldap typo again
6c2daa3 Fix #2783 - Puppetdoc rdoc should use environment to get modulepath/manifestdir
5648666 Add Environment#manifestdir and small refactoring
74a877e Minimal fix for #2821 ("rake spec" is needlessly slow)
cd10e6d Added package signing task
ca56aa7 Least kludgy patch for #2675
adc0a4e Fix for #2661 and related issues
65f601a Fixing 2806 Specifying multiple tags fails to apply any of them
e2c675e Updated generate function documentation to make it clear it runs on the master
53f40bd Fix #2681 Incorrectly duplicating resources
3fdc8ef Ticket #2770 (deserializing Exec[...]s with "\n"s)
b172287 Fixing #2767 invoke-rc.d warnings
4013560 Fix #2797 - tags are not inherited by recursed file sub child
f05a04e Fix #2784 - puppetdoc/rdoc didn't parse mono-instruction class content
38ec9fc Fix #2796 - Fix puppetdoc rdoc selector parsing
5f7177e Fix #2795 - puppetdoc rdoc reports a better error message
136949d Fixing #2631 show_diff sometimes doesn't happen
cb3e5e1 Fix #2787 - Storeconfig doesn't store/update node ip and environment anymore
ff23b57 Fix for #2670, Puppet silently ignores catalog_format
ee13efa Add docs to Mac OS X package creation script and clean out old docs in the preflight
b8470b8 Fix #2757 & CSR 92 (symlinks in recursively managed dirs)
5b750c2 Fix #2769 - default schedule are not defined
eca338c Fix for #2772 (webrick test failures)
b1c57e9 Al Hoang's patch for #2781, removing obsolete when/: syntax
50e9c98 Follow-on for #2724 - Adding an external node classifier
0.25.1
======
2f0b1e5 Updated CHANGELOG
20e5222 Fixing #2689 - file owner warnings are reduced
09fb3f7 Fixing #2752 - "require" loads "include"
6846c32 Fixing some recently broken Scope tests
0043392 Fixed typo in lib/puppet/indirector/ldap.rb
6b254eb Fix #2753 - Do not "global allow" plugins/modules mount if some rules have been parsed
ff3a7bc Re-fixed #2750 - Stop disabling the CRL or checking for a disabled CRL
594c774 Revised partial fix for #2661 and related issues
73d04c6 Bug #2534 Raise error if property appears twice
7517572 Bug #1908 cron environment should allow empty vals
febe707 Bug #1742 Invalid params to --color outputs 'nil'
d383ab8 Use notice() in the versioncmp() docs
9dff716 conf/redhat/*.init: Use -p option to killproc
f47a70f Ticket #2665: Regexp exception on ++ in package names
b6e4ef3 Fixed #2750 - Set :cacrl to nil instead of 'false' in puppetd
2b57e06 Fix #2691 - Collection AR request should not include params if querying with tags
e8bce7a Workaround #2668 - Compress facts so that the request size limit triggers less often
e2ce790 Fixed #2737 - The zone provider needs to get acquainted with OpenSolaris
aea1e5f Update Red Hat spec file for 0.25.1
fbdded7 Ticket #2685 (Type error in ssh_authorized_keys)
4d9f76a Fix for #2745 fakedata tests not working
b4bcfe9 Fix for #2736, target doesn't work for ssh_authorized_keys
ae528f6 Ticket #2734 PSON/JSON not serializing classes of a catalog
f59f805 Bug #1900 Parsing of quoted $ in stdin
6ba122f Fixing #2735 - node classes are immed. added to classlist
0.25.1rc2
=========
bca3b70 Bundling of pure ruby json lib as "pson"
ce46be5 Proposed alternative solution for #2664 (REGEX / DIV lexing)
b0518c3 Fix for #2681 (duplicate resource)
8a73082 Fix #2707 config_version fails more helpfully
54ded1b Fixes #1719, this avoids calling the external binary *which* everytime we are looking for a binary
4c3c279 Updated required Facter version in README
fcce46a Fixed #2702 - Set :outputdir to "doc" if not specified
3940dfb Fixed #2674 - createpackage.sh: problem finding install.rb
3b548f4 Fix #2699 - Use --masterport for PUPPET_PORT variable
a75bf50 This updates the portage provider in three ways:
ad86e9e Fixes #2688. Macauthorization provider now handles booleans internally correctly.
d891f7a Ticket #2676 (a typo)
bfba2cd Fix #2672 - Make sure nodenames keep their underscores when used as classname
db67e5f Added rcov exclusion to Rakefile
0.25.1rc1
=========
6912a7e Incremented version to 0.25.1
fd322da Fixes #1538 - Fixes the yumrepo backtrace in noop mode.
6551e86 Fix #2664 - Mathematic expressions mis-lexed as Regex
a595033 Fix for #2654 (error generating error message)
a951163 Fix #2642 - Runit provider rework
96b5087 Fix for ticket #2639 (Puppet[:user]/Puppet[:group] vs. 'service')
af57483 Fixing #2632 - 'require' works for 0.25 clients
d42bda1 Fixing relationship metaparam backward compatibility
d53bc16 Adding version information to the catalog for compat
5f25589 Ticket #2626 (unhelpfull error messages)
a1d3b04 Fixing #2617 - use the cert name as specified
8987509 Refactored Puppet packaging and gem creation
5c2ba47 FIXES 2616: Remove sync.syncronize and Puppet.info
a53a77c Renamed test branch to testing in rake task
d054fd9 Fixing #2656 - puppet parseonly tests don't hang
cde70cf Fixes #2648. Spurious macauthorization parameter changes
dcf0d0d Fix #2652 - Fix SELinux syntax error
ba269f2 Fixed #2651 - Corrected install permissions on man page directories.
361c502 Fix #2638 - Allow creating several nodes with matching names
2283605 Added automatically constructed test branch task and file
fd2a190 Fix for #2621 (JSON serialization of exec)
577a45b Fix #2622 - Puppetdoc in single manifest to console is broken
d2d7070 Fix #2640 - Daemontools and Runit were not creating the enable symlink
d21b266 Fix #2627 - regex node name could lead to invalid tag
cb90528 Merged fix for #2601
b1554a1 Updated changelog task and CHANGELOG to version aware
f5a106d Fix for #2637 (Webrick accpting connections on dead sockets)
19e98f9 Fixed #2608 - install.rb will not run on ruby 1.9.1 due to ftools being deprecated
40cd6d4 Fix for #2605 by falling back to alternative solution to #1963
630407d Make regsubst() function operate on arrays (feature #2491).
a45c435 Fix for #2600 (wrong number of arguments under older mongrel)
f2bc8aa Fixed #2634 - Added servicegroup_name parameter to serviceescalation type
7404e31 Fixs #2620 authconf interpolation, #2570 0-9 in domain names
4344339 Fix for ticket #2618 (stubbing so redhat tests run under debian)
c2e26b9 vim: match regexp language features
1494bd7 Require active_record/version to support ActiveRecord < 2.3
a5c56fc Fixed #2607 - Added Facter dependency for Puppet Gem
0.25.0
======
b1eddbb Updated and created new CHANGELOG format
994d6e0 Adding tests for the #2599 fix
42ab73f Ticket #2525 don't fail find_manifest on invalid module names
a0f0dcc Updated permissions on test files
d45812b Refactoring tests to reduce code size, increase coverage, and make Luke happy.
aba2f66 This further normalizes the handling of init-style services (including the redhat "service" wrapper script). Removes special case handling of non-zero exit code in redhat (base already did this) and centralizes scattered @resource[:has_____] checks. Tests that proper versions of each are called and one level of fallbacks.
fb236a0 Combined fix for #2525, #2552 -- RedHat service issues
d40b942 Fixed #2589 - Renamed zfs delete to destroy and added tests
4aa7fce Monkey patch to improve yaml compatibility between ruby versions
1f6c74d Fixed typo in parser test
2e9b706 Updated Red Hat spec file and RH patches for 0.25.0.
19815dd Fixing #2592 - you can escape slashes in regexes
ea58478 Fixing #2590 - modulepath is not cached inappropriately
1a3d0c8 Fixed #2593: puppet init script status command not returning proper exit code
8dabc72 Update documentation string to reflect actual intent of Puppet::Node::Facts::Rest
b30a3c7 Fixes #2581. Use new 10.6 global launchd overrides file for service status/enabled
7f05469 Fixed Naginator link
e589cd3 Fixing #2582 - / no longer autorequires /
3342b73 Fixing #2577 - clarifying and demoting the deprecation notice
d397f8d Fixing #2574 - autoloading finds plugins in modules
800a78b The first regex node now matches first
6750aeb Fixing #2563 - multiple regex nodes now work together
b728b93 Fixes #724 - false is equivalent to 'ruby -W1'
a9d5863 Fix parser error output
ee4f6ba Fixing #2551 - fixing content changed logs
c8f859e Fix for test isolation portion of Ticket #2511
6fa9271 Fixing #2549 - autoloading of top-level classes works again
c752680 Fixing a heisenbug resulting from a race condition
ea417d6 Fixing #2460 - puppetmasterd can now read the cert and key
a49915a Not using the service user in settings when it's unavailable
14ec838 Explicitly loading all facts in the directory service provider
5ee6602 Adding an 'exists?' delegator from user type to provider
06fcece Switching the owner/group settings to use symbolic values
4eb325a Fixing the yamldir group to be a group instead of user
058514a Moving Setting classes into separate files
b0f219a Removing chuser on darwin restriction
7f749cb Fixing a ruby warning in the authstore test
c0da3bf Fixing #2558 - propagating recent fileserving changes
ff39bc7 Fixes #2550 Handles case where metadata is nil
47dee83 Ticket 2559 -- parseonly ignored specified file
a4f6896 Fixed #2562 - Recognize the usecacheonfailure option again Signed-off-by: John A. Barbuto <jbarbuto@corp.sourceforge.com>
e408d6c Refactoring the Module/Environment co-interface
796ba5c Fixing #1544 - plugins in modules now works again
6bd3627 Adding a global cleanup to the spec_helper
0ef5f22 Removed misguided case sensitivity tests
c1967bb Fixes #2513. debian service provider now uses invoke-rc.d to determine enabled? status
7e09247 Fixing fact-missing problem when puppet.conf is reparsed
a35e9bf Fix for #2531; adds tests to confirm problem and related cases, notes fixes specific issue by eliminating the specal case for opaque strings which caused them to be strings when everything else was arrays; adds nots and pending tests where FQDN support could be added but stops short of a full refactor.
299eadb Fixed #2530 - Fixed status setting in the SMF provider
e6a7e82 Fixed spec typo
75c6e4a Fixes #2493
b62d966 conf/redhat/*.init: Fix condrestart/try-restart
e9fbd4c conf/redhat/client.init: Fix #2123, status options on older RHEL
0461a02 Updates to Solaris smf files to reflect new binary locations
55a9cdb Fix #2517 - Stack overflow when CA cert missing
601a2e5 Fix #2516 - Fix format detection when content-type contains charset
d86bc88 Fix #2507 - Add missing integration tests
aad3b76 Fix #2507 - Exported resources were not correctly collected.
63cb1ad Fixes #2503
c129f2a Fixes #2360 - Removed annoying log message
b1ffffa Fixed #2525 - Wrong method being overridden in Red Hat services
a88fc4d Fixing more tests broken from missing libraries
9a356ab Fixing ActiveRecord Indirector tests to skip w/out Rails
acc5a96 Fixing #2489 - queue integration tests are skipped w/out json
1a5c5b3 Fixing #2508 - removing mention of ActiveRecord 2.3
0cb9072 Fixing #2541 - file cache is more resilient to failure
23948d0 vim: Mark puppetFunction values as contained
79a4339 Add shellquote() function.
79d705f Fixes #2499. Allows execs to specify an array for the returns parameter
b611c34 Updated fix for #2481
f385072 Revert "Fxied #2481 - Added status and restart overrides for Red Hat service provider."
cc379b6 Fixed #2498 - logcheck update
85a3633 Removed extraneous debugging
0.25.0rc1
=========
bf94de9 Updated two more tests
5b87dba Logs now assume resource params have metadata
1410bed Adding metadata delegation from param to resource
3ab3a5c Removing unnecessary debug output
488e368 Adding integration tests for #2371 (backup refactor)
f1406bf Adding many tests for #2371, and slightly refactoring
8f60f0c Fixes for Redmine 2371.
cd224c6 Fixes #2464, #2457. Deprecate reportserver for report_server. Add report_port setting. Add tests.
401a9ec Fixing #2484 - "format missing" messages are better
f6cc598 Fixes #2483 - Log only copies metadata from RAL objects
7c4c00f Fixed #2486 - Missing require 'monitor' in parser_support.rb
ea34ee6 Added R.I.Pienaar's extlookup.rb to the ext directory
36d3f58 Added example conf/puppet-queue.conf
967eb9f Fxied #2481 - Added status and restart overrides for Red Hat service provider.
c702f76 rack: SSL Env vars can be in Request.env or ENV
ca17b3c rack: don't directly use the forbidden HTTP_CONTENT_TYPE env var (fixes rack specification conformance)
a002e58 Removing old filebucket test
d8de446 Cleaning up tests for #2469
266aafa default server in remote filebuckets
1f8ef60 Fixes #2444 - Various JSON test failures
11c0fb7 Fixed #2294 - Classes sometimes cannot be found
7e5b562 Adding #2477 - puppet can apply provided catalogs
97274ad Fixing problems my Feature refactor caused
6fb8bf6 Fixing ruby warning in definition test
b3545fc Fixed global deprecation error in useradd Unit tests
dc24472 Adding a test for the Exec type
58d9587 Speeding a test up through stubbing
d4d8372 Fixing a small test by stubbing instead of mocking
f7e1c36 Fixing a test broken by the regex features
54a225d Fixing tests broken by caching autoload results
1ce31b4 Migrating Handler base tests from test/ to spec/
cc3f56a Migrating Feature tests to spec
21d1d25 Fixing cron test to match new behaviour
849fa67 Migrating tests to spec and removing an obsolete test
6f458cc Logging the configuration version we're applying
ac58e27 Configuration version information is now in logs
6ed0103 Adding support for an external catalog version
39320b8 Cleaning up duplication in another test file
25fae5f Removing duplication in the test structure
36c0662 Simplified Rakefile and moved tasks to tasks/rake directorya
b45ccf8 Implement node matching with regexes
58a73b5 Make sure node are referenced by their names
3ebf148 Enhance selector and case statements to match with regexp
ef68967 Fix #2033 - Allow regexp in if expression
17e62b1 Add AST::Regex, an AST leaf node representing a regex
4f9545f Add regexes and regex match operators to the parser
0ccd259 Add regex, match and not match token to the lexer
201ae59 Allow variable $0 to $9 to be interpolated, if ephemeral
f357a91 Implement ephemeral scope variables
d40ef29 Signed-off-by: Eric Sorenson <ahpook@gmail.com>
6d22afb Modifying the REST client error to make server errors more clear
21f477a Fixes #2472. Load Facter facts when ralsh is invoked, plus test.
2e41edb Update CHANGELOG.git
ebb5a1f Fixed ci_spec task for RubyGems 1.3.5
b6b903e Fixes #2461. Provide new and old code paths for macosx_productversion_major with deprecation warning
26b0c70 Fixing typo in two tests which caused them to always pass
76fc2b1 Fixing #2440 - catalogs can now be compiled on demand
832b6ff Exiting from app failures instead of raising
4ea3f17 Minimal patch to fix #2290 (/tmp permissions)
08ff9e8 Fix #2467 - rack: suggest putting puppet/lib at beginning of RUBYLIB search path
fb60f90 Fix #2465 - Default auth information is confusing with no auth.conf
0ca9b53 Fix #2459 - puppetdoc added namespace classes as RDoc modules instead of classes
18b5d61 Fix #2429 - vim: class/define/node should only be followed by whitespace
da828a4 Fix #2448 - fix the broken runit provider and tests
3898436 Fixed #2405 - Mount parameter "dump" doesn't accept all valid values on FreeBSD
9825bec Fixes #2362. Do not validate users/groups when supplied with numeric uid/gids
450a19c Fix #2454 - Definition named after a module don't show in puppetdoc
8551ece Fix #2453 - puppetdoc mixes long class names that look alike
e3ee594 Fix #2422 & #2433 - make sure puppetdoc transform AST::Leaf boolean correctly
b3b76df Fixing #2296 - overlapping recursions work again
9120712 Fixing mocks to remove warnings
eeec8e9 Fixing #2423 - no more strange dependency cycles
7d40f9e Fixing #2443: Adding debugging guidance to dep cycle errors
b4facb0 Fixing a test broken by changing the default os x package type
b418921 Fixing selinux tests broken in the fix for #1963
719e76b Fixing #2445 - fixing the mount test mock
f13f08d Minor fix to URL for LDAP nodes documentation
7c859a7 Fixing #2399 - removing client-side rrd graphs
f6d6145 Fixing #2421 - file renaming errors now propagate
db82523 Fixes #2438, get major OS X version from Facter and replace Puppet::Error invocations with fail builtin
22145e7 Update install.rb to cope with all OS X versions, not just 10.5
935c463 Fixing #2403 - provider specificity is richer and better
d95b687 Fix #2439 - let puppetdoc use loaded_code
ef5c4ae Fixed #2436 - Changed ralsh to use Puppet::Type.new and avoid deprecation notice
0c18013 Fixes #2430 - Stock apache2.conf for passenger incorrect
c383ceb Make pkgdmg default Darwin provider, make confines consistent on Darwin package providers.
98599c4 Convert to using sbindir for OS X packages, clean out previous executables in bindir
c659743 Fix #2425 - make sure client can contact CA server with REST
17205bb Fix #2424 - take 2, make sure default mounts allow every clients
f2c55cc Fix #2378 and #2391 tests
8bbd8b4 Fix #2424 - File server can't find module in environment
effaf80 Fix small typo in the fix for #2394
a06094e Feature #2378 - Implement "thin_storeconfigs"
b2a008e Fix #2391 - Exported resources never make to the storeconfigs db
8f82407 Fix #2261 - Make sure query string parameters are properly escaped
c86d44e Fixed #579 - puppet should try to clear solaris 10 services in maintenance state
910a5e2 Fix #1963 - Failing to read /proc/mounts for selinux kills file downloads
ba824e9 Fixing #2245 - provider lists are not lost on type reload
eb40966 Ruby no longer clobbers puppet autoloading
a42e878 deprecate NetInfo providers and examples, remove all NetInfo references and tests.
22f5632 Fixed #2410 - default acl logs as info instead of warn.
65b0137 Adding test for current auth config warning.
74f5ad4 Fixed #2394 - warn once on module mount deprecation.
f46a52a Add test for current module mount deprec warning.
858d333 Fixes #2258,#2257,#2256. Maintain correct type for integers/booleans, allow correct values, and fix rule array handling
44f127f Added Markdown mode to puppetdoc to output Markdown.
8a8ce9d Excluded directories from rcov coverage report
d152c5e Allow boolean value for boolean cli parameter
911b490 Fix #2364 - Associates the correct comment to the right statement
faefd92 Make sure the parser sees the correct line number
869ec27 Fix #2366 - puppetdoc was parsing classes in the wrong order
4c659b7 Added rcov coverage to Spec tests
1fd98b1 Fixes #2367 - Mongrel::HTTPRequest returns a StringIO object
8b09b83 Fix #2082 - puppetca shouldn't list revoked certificates
ea66cf6 Fix #2348 - Allow authstore (and REST auth) to match allow/deny against opaque strings
1e83aad Fix #2392 - use Content-Type for REST communication
aaca17a Fixed #2293 - Added cron syntax X-Y/Z and '7' for sunday
cddc365 Switching to LoadedCode from ASTSet
fc1f8cd Adding a special class to handle loaded classes/defines/nodes
325b8e4 Fix #2383, an incompatibility with early ruby 1.8 versions
46112da Fixing #2238 In some cases blank? is not available on String.
cdd1662 Fixing #2238 - Deal with nil hash keys from mongrel params
769c8aa Final fix to CI test rakes
a6816ff Set ENV['PATH'] to an empty string if non-existent
64a4720 Fix to CI rake tasks
5680cd5 Fixing #2197 - daemontools tests now pass
603b9cf Change the diff default output to "unified"
9bc9b5c Added missing colon to suntab
0f2d70d Fixed #2087 and refactored the code that gets the smf service state
0.25.0beta2
===========
3f070c1 Using the logging utilities to clean up module warnings
feb7f89 Fixing #1064 - Deprecating module 'plugins' directories
ccf4e69 Removing deprecated :pluginpath setting
4036de9 Fixing #2094 - filebucket failures are clearer now
ed876e0 Refactoring part of the file/filebucket integration
bd81c25 Adding tests for file/backup behaviour
c45ebfa Fixed pi binary so --meta option works and updated documentation
d2080a5 Fixing #2323 - Modules use environments correctly
b9e632f Fixed #2102 - Rails feature update fixed for Debian and Ubuntu
1c4ef61 Fixed #2052 - Added -e option to puppet --help output
d332333 Fix #2333 - Make sure lexer skip whitespace on non-token
5fbf63c Updated split function and add split function unit tests (courtesy of Thomas Bellman)
a585bdd * provider/augeas: strip whitespace and ignore blank lines
a94d2de Fixed pi tests
5f7455e Fixed #2222 - Cleanup pi binary options and --help output
134ae3e Fixing #2329 - puppetqd tests now pass
de55e19 Cleaning up scope tests a bit
e4ae870 Fixing #2336 - qualified variables only throw warnings
607b01e Fix #2246 - take2: make sure we run the rails tag query only when needed
06b919d Fix collector specs which were not working
2945f8d Make sure overriding a tag also produces a tag
e142ca6 Removed a unit test which tested munging which is no longer done in the type
d8ee6cf Clearn up a parsing error reported by the tests
446557f vim: several improvements + cleanup
9152678 Fixed #2229 - Red Hat init script error
b5a8c4d Fix #1907 (or sort) - 'require' puppet function
74730df #2332: Remove trailing slashes from path commands in the plugin
1a89455 Changing the preferred serialization format to json
0de70b7 Switching Queueing to using JSON instead of YAML
7b33b6d Adding JSON support to Catalogs
c0bd0aa Providing JSON support to the Resource class
c16fd1b Adding a JSON utility module for providing Ruby compat
f059c51 Adding JSON support to Puppet::Relationship
7f322b3 Adding a JSON format
7666597 Allowing formats to specify the individual method names to use
d40068f Allowing formats to specify the methods they require
024ccf5 Adding a "json" feature
c8b382d Fix some tests who were missing some actions
f9516d4 Make sure virtual and rails query use tags when tag are searched
b5855ec Make sure resources are tagged with the user tag on the server
d69fffb Fix #2246 - Array tagged resources can't be collected or exported
6ce0d1e Partial fix for #2329
4f2c066 Removed extra whitespace from end of lines
97e6975 Changed indentation to be more consistent with style guide (4 spaces per level)
41ce18c Changed tabs to spaces without interfering with indentation or alignment
f3b4092 Fix #2308 - Mongrel should use X-Forwarded-For
7b0413e Fixes Bug #2324 - Puppetd fails to start without rails
48d5e8c Enhance versioncmp documentation
ef56ba5 * provider/augeas: minor spec test cleanup
d322329 * provider/augeas: allow escaped whitespace and brackets in paths
9735c50 * provider/augeas: match comparison uses '==' and '!=' again
dbfa61b * provider/augeas (process_match): no match results in empty array
386923e * provider/augeas: remove useless checks for nil
171669a * provider/augeas: simplify evaluation in process_get/match
51cc752 * provider/augeas (open_augeas): use Augeas flag names, not ints
4951cdf * provider/augeas: ensure Augeas connection is always closed
0d5a24d * provider/augeas: minor code cleanup
cea7bb5 * provider/augeas (parse_commands): use split to split string into lines
95bd826 * provider/augeas: remove trailing whitespace (no functional change)
7c5125b Brought in lutters parse_commands patch and integrated it into the type. This includes reworking the get and match commands as well. This change introduces a few small changes. These are:
6ce8154 Removed --no-chain-reply-to in rake mail_patches task
4ef7bba Removing --no-thread from the mail_patches rake target
508934b Fixing a bunch of warnings
fb0ed7a Fixing tests broken by a recent fix to Cacher
650029e Always providing a value for 'exported' on Rails resources
f1dba91 Fixing #2230 - exported resources work again
5522eb8 Disabling the catalog cache, so puppetqd is compatible with storeconfigs
abbb282 Fixing the rails feature to be compatible with 2.1+
907b39b Using Message acknowledgement in queueing
42247f0 Fixing #2315 - ca --generate works again
d7be033 Fix #2220 - Make sure stat is refreshed while managing Files
e4d5966 Added puppet branding to format patch command
00d5139 vim: Remove another mention of 'site' from syntax
9067abd vim: Highlight parameters with 'plusignment' operator
736b0e4 vim: Highlight strings in single quotes
ce01c95 vim: Clean up syntax spacing
3af2dbf JRuby OpenSSL implementation is more strict than real ruby one and requires certificate serial number to be strictly positive.
62534a1 Logging when a cached catalog is used.
ff5c44f Changing Puppet::Cacher::Expirer#expired? method name
e3d4c8e Fixing #2240 - external node failures now log output
bc1445b Fixing #2237 - client_yaml dir is always created by puppetd
e0c19f9 Fixing #2228 - --logdest works again in puppetd and puppetmasterd
ab34cf6 Fixing puppetmasterd tests when missing rack
9d5d0a0 Fixing the Agent so puppetrun actually works server-side
b0ef08b Fixing #2248 - --no-client correctly leaves off client
b83b159 Fixing #2243 - puppetrun works again
3d2189f Fixed #2304 - Added naggen script to directly generate nagios configuration files from a StoreConfigs Rails database
700ad5b Sync conf/redhat/puppet.spec with Fedora/EPEL
3ec3f91 Fixed #2280 - Detailed exit codes fix
f98d49f Fixing #2253 - pluginsync failures propagate correctly
d860a2f Fixing a transaction test that had some broken plumbing
a728757 Refactoring resource generation slightly
6e824d8 Adding a Spec lib directory and moving tmpfile to it
1d69dbf Extracting a method from eval_resource in Transaction
7650fb2 Not trying to load files that get removed in pluginsyncing
3995e70 Fix #2300 - Update ssh_authorized_key documentation
cb4a4d3 Changed version to allow Rake to work. Minor edit to Rakefile
99f666f enable maillist on centos, redhat, fedora
e13befa Fixing #2288 - fixing the tests broken by my attr_ttl code
a406d58 Fix for #2234: test fails with old Rack version
c189b46 Fixing #2273 - file purging works more intuitively
138f19f Caching whether named autoloaded files are missing
415553e Adding caching of file metadata to the autoloader
d489a2b Adding modulepath caching to the Autoloader
5f1c228 Adding caching to the Environment class
047ab78 Adding TTL support to attribute caching
6a413d2 Fixed #2666 - Broken docstring formatting
469604f Deprecating factsync - pluginsync should be used instead
d39c485 Added spec and unit tests to the Rakefile files list and fixed CI rake tasks
e1a7f84 Added install.rb to Rakefile package task
e180a91 Fixed #2271 - Fix to puppetd documentation
4bf2980 Protecting Stomp client against internal failures
f4cb8f3 Adding some usability bits to puppetqd
a18298a Refactoring the stomp client and tests a bit
2771918 Relying on threads rather than sleeping for puppetqd
07ff4be Fixing #2250 - Missing templates throw a helpful error
7ce42da Fixing #2273 - CA location is set correctly in puppetca
e1779c7 RackXMLRPC: buffer request contents in memory, as a real string.
fb957cc Modules now can find their own paths
c608409 Moving file-searching code out of Puppet::Module
83ba0e5 Fixing #2234 - fixing all of the tests broken by my bindaddress fix
4f3a67f Fixing #2221 - pluginsignore should work again
2d580c2 Fix snippets tests failing because of activated storeconfigs
8c718c9 Fix failing test: file.close! and file.path ordering fix
17f2c7d Confine stomp tests to Stomp enabled systems
6a80b76 Fix some master failing tests
172422f Fix bug #2124 - ssh_authorized_key always changes target if target is not defined
f945b66 Fixing #2265 - rack is loaded with features rather than manually
5aef915 Added .git to pluginsignore default list of ignores
6db5e8d Cleanup of the Puppet Rakefile and removal of the requirement for the Reductive Build Library
5cc4910 Fix #1409 once again, including test
a6af5bf Added split function
0.25.0beta1
===========
2dd55fc Fixing #2200 - puppetqd expects Daemon to be a class
c016062 Removing unneeded test stubs
1a2e1bc Fixing #2195 - the Server class handles bindaddress
df3a8f6 Minor fixes to function RST documentation
305fa80 Remove the old 0.24.x rack support, which is now useless cruft
d85d73c puppetmasterd can now run as a standard Rack application (config.ru-style)
d6be4e1 Add XMLRPC compatibility for Rack
6e01e7a Puppet as a Rack application
cc09c1a Use FileCollection to store the pathname part of files
d51d87e Add an unmunge capability to type parameters and properties
a1c0ae0 Fix #2218 - Ruby YAML bug prevents reloading catalog in puppetd
bf054e1 Fixes #2209 - Spec is failing due to a missing require
1c46205 Fix #2207 - type was doing its own tag management leading to subtile bugs
929130b Moved puppetqd binary
36d0418 Fixed #2188 - Added set require to simple_graph.rb
51af239 Fixed puppetqd require and tweaked stomp library error message
dc0a997 Fixes #2196 - Add sharedscripts directive to logrotate
4d3b54e Added puppetqd binary to Rakefile
1fee506 Updated version to 0.25.0beta1
0fbff61 Updates to CI tasks
aa6dcef Fixing #2183 - checksum buffer size is now 4096b
c0b119a Fixing #2187 - Puppet::Resource is expected by Rails support
5ec4f66 Adding an 'Exported' attribute to Puppet::Resource
adff2c5 Removing a non-functional and horrible test
606a689 Making sure the cert name is searched first
f489c30 Removing an "inspect" method that often failed in testing
93c3892 Removing deprecated concurrency setting usage in rails
6f8900d Always making sure graph edges appear first
3f7cd18 Reverting part of the switch to sets in SimpleGraph
bf46db7 Fixing rails feature test
5f6b5c0 Failing to enable storeconfigs if ActiveRecord isn't available
8ed7ae3 Fixing the Rails feature test to require 2.3.x
a0c1ede Modifying the Settings#handlearg prototype
284cbeb Fixes #2172 - service provider for gentoo fails with ambiguous suffixes
68ba1f1 SMF import support working and documentation update
f1f0a57 Fixes #2145 and #2146
ec478da Fix configurer to retrieve catalog with client certname
e623f8a Unify auth/unauthenticated request authorization system
037a4ac Allow REST auth system to restrict an ACL to authenticated or unauthenticated request
3ad7960 Fill REST request node with reverse lookup of IP address
c0c8245 Refactor rest authorization to raise exceptions deeper
aac996e Add environment support in the REST authorization layer
72e28ae Fix some indirector failing tests
dc1cd6f Fix #1875 - Add a REST authorization system
8523376 Enhance authconfig format to support uri paths and regex
22b82ab Add dynamic authorization to authstore
15abe17 Add RSpec unit tests for network rights
86c7977 Add RSpec unit tests for authconfig
f04a938 Adding support for specifying a preferred serialization format
6a51f6f Fixing the FormatHandler test to use symbols for format names
b249f87 Fixing #2149 - Facts are passed as part of the catalog request
1cde0ae Adding better logging when cached indirection resources are used
828b1ea Fixing #2182 - SimpleGraph#walk is now iterative
9f32172 Fixing #2181 - Using Sets instead of Arrays in SimpleGraph
7a98459 Removing code that was backported and is now not needed
d06bd3e Finishing class renames
b694b3c Fixing tests that apparently only worked sometimes
93246c0 Removing the old rails tests.
5cb0f76 Fixing some rails tests that sometimes failed
bdbf9db Added class_name tags to has_many relationships
2e62507 Adding time debugging for catalog storage to active_record
a705809 Adding defaults necessary for queueing
8a67a5c Adding daemonization to puppetqd
fcd1390 Adding Queueing README
9b90f34 Using a setting for configuring queueing
444ae9f Adding puppetqd executable.
22ae661 Adding "rubygems" and "stomp" features
efe6816 Removing unnecessary parser variables when yaml-dumping
a3b1e8c Add queue indirection as an option for catalog storage.
bccfcc9 Introduce abstract queue terminus within the indirection system.
7947f10 Introduce queue client "plugin" namespace and interface, with a Stomp client implementation.
80dc837 renaming a method
f7ccaaa Adjusted parameter name and puppet tag classes to use new cache accumulator behavior for storeconfigs.
75f1923 Initial implementation of a "cache accumulator" behavior.
bab45c4 Saving rails resources as I create them, which saves about 10%
7a91e1f Changing rails value serialization to deal with booleans
c30ede5 Adding equality to ResourceReference
589f40f Adding some more fine-grained benchmarks to Rails support
042689e Adding a Rails-specific benchmarking module
89d9139 Adding simplistic param_name/puppet_tag caching
ea4e3b2 Adding more time debugging to Rails code, and refactoring a bit
6314745 Refactoring the Rails integration
be30a61 Adding a common Settings method for setting values
863c50b Switching to Indirected ActiveRecord
a137146 Adding ActiveRecord terminus classes for Catalog
b9c95eb Adding ActiveRecord terminus classes for Node and Facts.
8d0e997 Fixing #2180 - Catalogs yaml dump the resource table first
4e0de38 Partially fixing #1765 - node searching supports strict hostname checking
c1f562d Removing unused Node code
e6b4200 Fixing #1885 - Relationships metaparams do not cascade
50e0f3d Fix #2142 - Convert pkgdmg provider to use plists instead of string scanning for future proofing
c1be887 Fixing #2171 - All certificate files are written with default perms
e2201d6 Fix #2173 - fix running RSpec test by hand
424c87b Fix #2174 - Fix RSpec rake targets
7ab7d9f Fixing #2112 - Transactions handle conflicting generated resources
84e6c1b Adding another stacktrace for debugging
4793334 Fixing puppet -e; it got broken in the move to Application
7398fa1 Partially fixing #2029 - failed caches doesn't throw an exception
88ff9c6 Fixing #2111 - SimpleGraph only creates valid adjacencies
36594fe Switching to new() in the Puppet::Type.instances() class method
edcbab5 Removing duplicate method definition from SimpleGraph
d8eaca8 mini daemon to trigger puppetrun on clients without puppet listen mode
d2c417e Fix #2113 - Make temp directory
173b5f0 Adding #2122 - you can specify the node to test with puppet-test
a677e26 Fixing all tests that were apparently broken in the 0.24.x merge.
e016307 Fixing Rakefile; apparently there was a rake or gem incompatibility
62dad7a Fix #2107 - flatten resource references arrays properly
cbee426 Fix #2101 - Return to recurse=0 == no recursion behavior
3b4816b Fix #2101 - fix failing test
f089e11 Fix #2101 - fix recurselimit == 0 bad behaviour
1b4eae7 Added rake ci:all task
3f61df8 Fixed #2110 - versioncmp broken
830e1b1 CHANGELOG updates
3e0a9cd Moved of puppetd, puppetca, puppetmasterd, puppetrun binary from bin to sbin
6ddebf4 Fixed #2086 - Fixes to make building tarballs easier
33d3624 Fix #1469 - Add an option to recurse only on remote side
77ade43 Forbidding REST clients to set the node or IP
0179e94 Fixing #1557 - Environments are now in REST URIs
a497263 Adding explicit optional attribute to indirection requests
3e95499 Removing an unused source file
97975e1 Adding a model accessor to the Request class
b6116fe Requests now use default environment when none is specified
15740fe Moving the REST API functions into a module
ef4fa68 Using the Handler for the REST api on both sides of the connection
8b13390 Adding REST::Handler methods for converting between indirection and uris
edf00db Adding environment support to the REST URI
a064ed1 Moving the query_string method to Request
ff9c3ca Adding tests for the REST query string usage
87ec08e Fixing #2108 - pi should work again
af4455e Fix #1088 - part2 - Add rspec tests
b15028f Fix #1088 - Collections overrides
b24b9f5 Fixed #2071 - Updated LDAP schema
88aa1bc Fixing tests broken in previous commits
f8dea98 Fixing #1949 - relationships now use attributes instead of a label
d0fc2f5 Correctly handling numerical REST arguments
90afd48 Not passing file sources on to child files
858480b Correctly handling non-string checksums
27aa210 Removing unnecessary calls to expire()
5329b8a Passing checksums around instead of file contents
71e4919 Moving default fileserving mount creation to the Configuration class
09bee91 Fixing #2028 - Better failures when a cert is found with no key
cf1cb14 Moving the clientyamldir setting into the puppetd section
5f73eb5 Fixed #1849 - Ruby 1.9 portability: `when' doesn't like colons, replace with semicolons
e40aea3 Fixed metaparameter reference to return str
5df9bad Fixed #2016 - Split metaparameters from types in reference documentation
7e207a1 Fixed #2017 - incorrect require
417b5a5 Fixing #1904 - aliases are no longer inherited by child files
c0d5037 Removing or fixing old tests
262937f Correctly handling URI escaping throughout the REST process
b800bde Refactoring how the Settings file is parsed
d7864be Relying on 'should_parse_config' in the 'puppet' application
bd8d097 Providing better indirection authorization errors
d3bc1e8 Adding pluginsyncing support to the Indirector
00726ba Moving Request and Fileset integration into Fileset.
058266f Switching the ModuleFiles Indirection terminus to the new Module/Env api
19b8534 Migrating the old FileServer to the new Module/Environment code
1be7c76 Using the Environments to handle a lot of Module searching
2b4469d Environments now use their own modulepath method.
94de526 The 'Environment' class can now calculate its modulepath.
2573ef1 Added support for finding modules from an environment
9c18d5a Adding support for finding all modules in a given path.
4b5ec82 reformatting the environment tests
458642b Supporting multiple paths for searching for files.
eec1cad Adding support for merging multiple filesets.
bdf3a80 Adding new methods to Puppet::Module.
a7be174 Refactoring Puppet::Module a bit.
7ceb437 Only using the checksum cache when we're using a host_config catalog
5fd182d Fixing fileserving to support strings or symbols
7bc41ce Adding clarity to query string handling in REST calls
992231a Some small fixes to provide better debugging and load a library
0304a78 Providing better information when an exception is encountered during network communication
4a7cba3 Stubbing tests that were affecting other tests
3105b5b Fixing a warning in a test
c854c59 Fixing a syntactically invalid application test
0f43fd6 Move --version handling to Puppet::Application
156fb81 Move puppetd to the Application Controller paradigm
0c71c5c Move puppetdoc to the Application Controller paradigm
e317fa9 Move ralsh to the Application Controller paradigm
81f5438 Move puppetrun to Application Controller paradigm
3390d8d Move pi to the Application Controller paradigm
8265d6e Move puppetmasterd to Puppet::Application
af219bf Move puppet to the Application Controller paradigm
d51398c Move filebucket to the Application Controller paradigm
9b9e5e8 Move puppetca to the Application Controller paradigm
97e716a Introducing the Application Controller
495ad66 Fixing broken filetype tests resulting from the loss of Type[]
21a714a Fixing some tests that somehow broke in the merge to master
327ee17 Removing a test that was too dependant on order.
487b9b1 Failure to find node facts is now a failure.
610c838 Fixing #1527 - Failing Facter does not hurt Puppet
a2eca6c Removing some unused code
cb0a083 Using Puppet::Type.new instead of create
84bd528 Actualling syncing facts and plugins
d5abdfb Fix #1933 - Inconsistent resource evaluation order in subsequent evaluation runs
9bac833 Adding README.rst file
916abc2 Changing how the Configurer interacts with the cache
5335788 Fixing tests broken during the #1405 fix.
08a5d49 Adding an Agent::Runner class.
c7d178d The Agent now uses its lockfile to determine running state
c0fcb21 Creating and using a new Puppet::Daemon class
700e823 Not using 'master' client for testing
4b7023e Fixing (and testing) the return of Indirection#save
8dc0005 Adding a 'close_all' method to the Log class.
37d1a7c Removing restart-handling from Configurer
bf3c72e Adding temporary class EventManager
fc14b81 Splitting the Agent class into Agent and Configurer
e8be6dc Removing the Hash default proc from SimpleGraph.
6bb804f Removing the Catalog's @aliases hash default value
502e062 Removing an erroneous configuration call in puppetmasterd
337057a Removing obsolete code and tests for the agent.
d53ad31 Converting the catalog as needed
f38277f Adding REST support for facts and catalogs.
c48525b Adding better error-handling to format rendering
b93a642 Resetting SSL cache terminii to nil when only using the ca
212b3e3 Allowing the Indirection cache to be reset to nil
5a83531 Moving the Agent locking code to a module.
b672790 Cleaning up SSL instances that can't be saved
f78a565 Only caching saved resources when the main save works
5434459 Moving classfile-writing to the Catalog
e65d7f1 Refactoring how the Facter integration works
6b4e5f4 Reformatting tests for facts
54faf78 Moving fact and plugin handling into modules
9d76b70 Removing the Agent code that added client-side facts
a5c2d7a Adding Puppet client facts to Facter facts.
b99c6b5 Clarifying how node names are used during catalog compilation
8b44d6f Reformatting Indirector catalog compiler tests
e770e7a Removing ConfigStore code that was never actually used.
37692e5 Renmaing Puppet::Network::Client::Master to Puppet::Agent
15d8768 Revert "Adding the first bits of an Agent class."
63fb514 Revert "This is work that I've decided not to keep"
8f5cbc3 This is work that I've decided not to keep so I'm just applying it here so it continues to show up in the history in case I ever want to look at it again.
25b28c5 Adding a new Agent::Downloader class for downloading files.
1afb821 Adding the first bits of an Agent class.
2afff60 Adding support for skipping cached indirection instances.
361db45 Change the way the tags and params are handled in rails
62cdeaa Add methods to return hash instead of objects to params and tags
3acea41 Rails serialization module to help serialize/unserialize some Puppet Objects
10bf151 Fixing #1913 - 'undef' resource values do not get copied to the db
500ea20 Fixing #1914 - 'undef' relationship metaparameters do not stack
1407865 Revert "Fixed #1916 - Added environment option to puppetd"
8d0086b Fixed #1916 - Added environment option to puppetd
a065aeb Fixed #1910 - Updated logcheck regex
fa9dc73 Typo fix
7c8094c Fixed #1879 - Added to tidy documentation
f40a6b1 Fixed #1881 - Added md5lite explanation
6af3179 Fixed #1877 - Tidy type reference update for use of 0
a5b0a75 Fix autotest on win32
234a035 Fix #1560
fb8f8cd In order for ReST formatting to work properly, newlines and indentation of doc strings must be retained.
69432d6 Fix Bug #1629
1f6dce5 Fix #1835 : Add whitespace/quote parsing to
8142981 Fix #1847 - Force re-examination of all files to generate correct indices
d2d3de5 Fix #1829 - Add puppet function versioncmp to compare versions
bdee116 Fix #1828 - Scope.number? wasn't strict enough and could produce wrong results
d69abfe Fix #1807 - make Puppet::Util::Package.versioncmp a module function
34335b7 Fixed #1840 - Bug fixes and improvements for Emacs puppet-mode.el
3b8a77d Fix #1834 part2 - Fix tests when no rails
b6e34b7 Fix #1834 part1 - Fix tempfile failing tests
566bf78 Fixing #1729 - puppetmasterd can now read certs at startup
0cf9dec Canonicalizing Setting section names to symbols.
0fc0674 Fixing all of the test/ tests I broke in previous dev.
e4ba3db Deprecating the Puppet::Type.create.
b6db545 Deprecating 'Puppet.type'; replacing all instances with Puppet::Type.type
89c25ad Finishing the work to use Puppet::Resource instead of TransObject
1c7f8f6 Adding name/namevar abstraction to Puppet::Resource.
e601bab Supporting a nil expirer on cacher objects.
f69ac9f Setting resource defaults immediately.
352d7be Refactoring the Settings class to use Puppet::Resource
91ff7c1 TransObject is nearly deprecated now.
fae3075 Simplifying the initialization interface for References
14c3c54 Replacing TransObject usage with Puppet::Resource
60062e4 Renaming the "Catalog#to_type" method to "Catalog#to_ral"
6b14000 Using Puppet::Resource to convert parser resources to RAL resources
e3b1590 Adding resource convertion to the parser resources
c306a17 Adding equality testing to Puppet::Resource::Reference
48a9949 Correcting whitespace and nested describes in Puppet::Resource::Catalog
d48fff6 Renaming Puppet::Node::Catalog to Puppet::Resource::Catalog
c927ce0 Renaming Puppet::ResourceReference to Puppet::Resource::Reference
e88746b Adding Trans{Object,Bucket} backward compatibility to Puppet::Resource
832198f Starting on #1808 - Added a base resource class.
820ff2e Removing the "clear" from the macauthorization tests
89e9ef7 Fix #1483 - protect report terminus_class when testing for REST
435f1e9 Fix #1483 - use REST to transmit reports over the wire
6b30171 Fixing all broken tests. Most of them were broken by fileserving changes.
f73e13e Adding more file tests and fixing conflicting tests
cc12970 Completely refactoring the tidy type.
720dcbe Cleaning up the tidy type a bit
053d7bf These changes are all about making sure file data is expired when appropriate.
a8d9976 Catalogs always consider resource data to be expired if not mid-transaction.
8b08439 Properly cleaning up ssl ca configuration during testing
73fa397 Adding caching support to parameters, and using cached attributes for file source and metadata.
0ecbf79 Adding cached attribute support to resources.
29b9794 Allowing a nil expirer for caching classes.
cd09d6b Refactoring the Cacher interface to always require attribute declaration.
14af971 Changing the Cacher.invalidate method to Cacher.expire.
99a0770 Fixing a critical bug in the Cacher module.
fe0b818 Fixing tests broken by fileserving and other refactoring.
eed37f7 Fixing a test broken by previous refactoring
45c6382 Finishing the refactoring of the resource generation interface.
0840719 Refactoring and clarifying the resource generation methods.
cc04646 Refactoring Catalog#add_resource to correctly handle implicit resources.
a73cad9 Adding SimpleGraph#leaves, which I apparently did not migrate from PGraph
2a685f9 Removing mention of obsolete edgelist_class from GRATR.
7e20f06 Changing the catalog's relationship graph into a normal graph.
2ba0336 Removing the PGraph class and subsuming it into SimpleGraph.
e92c1cc Moving Catalog#write_graph to SimpleGraph, where it belongs.
0149e2e Converting the file 'source' property to a parameter.
35c623e Removing mid-transaction resources from the catalog.
f4800e8 Adding a method to Checksums to extract the sum type
44fadd1 Aliasing "must_not" just like we alias "must"
a9dbb5d Deduplicating slashes in the fileserving code
bb6619a Fixing the augeas type tests to work when augeas is missing
e728873 Reducing the number of calls to terminus() to reduce interference with caching
aa8d091 Switched all value management in props/params to internal classes.
e5b5033 Fixing #1677 - fixing the selinux tests in master.
77d73e0 Changing the meaning of the unused Puppet::Type#parameter method to return an instance rather than a value.
05e1325 Moving a file purging test to rspec
6f7ccff Fixing #1641 - file recursion now only passes original parameters to child resources.
a4d4444 Removing obsolete methods and tests: Removing obsolete handleignore method Removing obsolete FileSource class Removing a now-obsolete test/unit test Removing a now-obsolete recursive filebucket test
b4f4866 Making it so (once again) files with sources set can still be deleted (which I think is kinda stupid, but apparently people want it).
caf15c2 Fixing and migrating more file tests.
cccd838 Adding a starting point for spec tests for tidy.
255c9fb Setting puppetmasterd up to serve all indirected classes.
7fdf2bb Retrieving the CA certificate before the client certificate.
a00c1f2 Handling the case where a symbol (e.g., :ca) is used for a certificate name.
cf3a11c Fixing :bindaddress setting to work with the new server subsystem.
a78c971 Fixing CertificateRequest#save to accept arguments.
e70c1a0 Fixing forward-compatibility issues resulting from no global resources
4596d2d Fixing a test I broke when fixing a reporting bug
9742c26 Fixing resource aliasing to not use global resource aliasing. I'm not really sure why the 0.24.x-style code got merged in, since master's changes should be more recent.
1b517d2 Adding comments to Puppet::Util::Cacher
7a6d9b1 Removing obselete code from the file type.
1b512a9 Merged fsweetser's selinux patch against HEAD
e31df2f Removing files that git wasn't smart enough to remote during a merge.
ac5db5e Removing the old, obsolete recursion methods.
a9b7f08 As far as I can tell, recursion is working entirely.
b69c50c Removing insanely stupid default property behaviour.
45f465b Source recursion is nearly working.
93fc113 Files now use the Indirector to recurse locally.
bd1163a Fixing filesets to allow nil ignore values.
5da2606 Recursion using REST seems to almost work.
ee1a85d Mostly finishing refactoring file recursion to use REST.
7c68fdb Fixing FileServing::Base so that it can recurse on a single file.
ac41987 Fixing the terminus helper so it correctly catches options passed from clients via REST.
be4c0e7 The file source is now refactored and uses REST.
44c6a52 Removing mention of an obselete class.
8271424 One third done refactoring file[:source] -- retrieve() is done.
98ac24a Adding a "source" attribute to fileserving instances.
6e43c2d Aliasing RSpec's :should method to :must.
8b45d13 Adding automatic attribute collection to the new fileserving code.
6ed8dfa Adding the content writer to the content class.
92e144b Fixing a test in the module_files terminus
151a54f Causing format selection to fail intelligently if no suitable format can be picked.
deda646 Removing the last vestiges of the 'puppetmounts' protocol marker.
30dea68 Adding a 'plural?' method to the Indirection::Request class.
40e76fb Fixing the rest backends for webrick and mongrel so the get the whole request key.
8ea25ef Refactoring how files in FileServing are named.
550e3d6 Finishing the rename of FileBase => Base.
90e7022 Adding weights to network formats, and sorting them based on the weight.
5a195e0 Renaming FileServing::FileBase to FileServing::Base.
3101ea2 Adding a hackish raw format.
89a3738 Adding suitability as a requirement for a format being supported.
a0bda85 Removing the yaml conversion code from FileContent.
6335b14 Causing the Indirection to fail if a terminus selection hook does not return a value.
1104edb Correcting whitespace in a test
2f224c9 Spell-correcting a comment
bcd40fb Cleaning up an exception.
0a05720 FileServing Configurations now expect unqualified files.
237b7b2 Fixing whitespace in docs of some tests.
91b8252 Fixing the fileserving terminus selection hook.
f5ba99f Special-casing 'file' URIs in the indirection requests.
a215aba Dividing server/port configuration responsibility between the REST terminus and the indirection request.
d174605 Fixing a test that relied on hash ordering.
7034882 Adding parameter and URL support to the REST terminus.
c819042 Fixing the String format (fixes #1522).
78bc32d Removing dead-end file work as promised.
a5ab52c Adding files temporarily, since I've decided this work is a dead-end.
4f275b6 Fixing #1514 - format tests now work again.
025edc5 puppetd now uses the Indirected SSL.
62202bf Adding 'require' statements as necessary for Puppet::SSL to work.
86a7188 Fixing the SSL::Host#waitforcert method.
a31c578 Adding logging when files are removed.
09ee814 Removing now-obsolete the wait-for-cert module.
cd314fa Documenting a bit of a test
113d74a Certificates now work over REST.
2cad30a Caching the SSL store for the SSL Host.
93fd55f Enhancing formatting errors with class and format.
6c80e0f Making all certificates only support the plaintext format.
c464bf2 Adding wait_for_cert functionality to the ssl host class.
c854dbe Adding a plaintext network format.
818599d lazy load latest package definitions with yumhelper 2.2
8457856 Fixing a group test that failed after merging 0.24.x
c2c8941 Correctly handling when REST searches return nothing.
186f3cd Removing an obsolete method from the rest indirector
29d704c The REST formats are now fully functional, with yaml and marshal support.
c55acee Adding some support for case insensivity in format names.
8033bd4 Moving validation from FormatHandler to Format.
3405841 Moving functionality out of the FormatHandler into the Format class.
43a6911 Searching again works over REST, including full content-type translation.
1064b5b Fixing the format_handler tests so that they clean up after themselves.
167831e Fixing a test I broke while rebasing
e78b1a6 Fixing a test to be order-independent.
352e2d0 Adding rudimentary support for directly managing formats.
55e2944 Adding support for rendering and converting multiple instances.
4632cfd All error and format handling works over REST except searching.
e3350ca Drastically simplifying the REST implementation tests.
b3914c3 Removing an apparently-obsolete hook from the handler
739a871 Adding explicit tests for the HTTP::Handler module.
0ce92f1 The REST terminus now uses the content-type and http result codes.
a4170ba Removing a now-obsolete pending test.
bf5b086 The REST terminus now provides an Accept header with supported formats.
1f15725 Using the FormatHandler in indirected classes automatically.
0e7e16d Adding a FormatHandler module for managing format conversions.
93eeff5 Fixing the user ldap provider tests
00b7da3 Fixing the new-form version of #1382.
c542dc0 Fixing #1168 for REST -- all ssl classes downcase their names. This is a much cleaner fix than the xmlrpc version, thankfully. :)
eaa6eab Fixing #1258 -- Removing a Rails idiom.
eb5e422 Fixing #1256 -- CA tests now work with no ~/.puppet.
66c36f0 Fixing another failing test -- the new CA tests correctly clear the cache.
447507c Fixing #1245 -- ssh_authorized_keys tests work in master.
6f533d1 Fixing #1247 -- no more clear_cache failures.
3cb0d60 Fixing how the mongrel server sets up xmlrpc handlers.
6efe400 Using the new Cacher class for handling cached data.
68d8d0a Adding a module for handling caching information.
e936ef2 Fixing some broken tests.
1cfb021 The CRL is now automatically used or ignored.
0365184 Removing obsolete tests
3303590 The master and client now successfully speak xmlrpc using the new system.
8fd68e3 Adding pidfile management and daemonization to the Server class.
dd4d868 Fixing the HttpPool module to get rid of an infinite loop.
57c7534 Adding REST terminuses for the SSL-related indirections.
d78b4ba Adding autosigning to the new CA.
a822ef9 Moving the CA Interface class to a separate file.
38e2dcf The master is now functionally serving REST and xmlrpc.
6e0d6dd The REST infrastructure now correctly the SSL certificates.
51ce674 Fixing the webrick integration tests to use the newly-functional SSL code.
62f1f5e The Certificate Authority now automatically creates a CRL when appropriate.
e57436f The Settings class now clears the 'used' sections when a value is changed.
137e29f Moving some http configuration values to the main defaults section, rather than the puppetd section.
a3b8804 The http pool manager now uses new-style certificate management.
e596bc5 Fixing some tests that were insufficiently mocking their configurations.
160f9d9 Fixing a critical problem in how CRLs were saved and moving SSL Store responsibilities to the SSL::Host class.
ce6d578 The SSL::Host class now uses the CA to generate its certificate when appropriate.
67dc268 The CA now initializes itself.
6356c04 Switched puppetmasterd to use the new-style server plumbing.
4c590df Adding xmlrpc backward compatibility to the new Mongrel code.
31b79fa Adding xmlrpc support to webrick.
7a876ed Fixing some whitespace
7267341 Adding configuration support for XMLRPC handlers.
8c9b04d I think I've now got the Webrick SSL support working. Now I just need to get xmlrpc working alongside REST in both mongrel and webrick.
83519f4 Interim commit, since I want to work but have no network available.
58fb416 Changing the File certificate terminus so that it saves to the :localcacert instead of :cacert.
79ca444 Renaming the 'ca_file' ssl terminus type to 'ca'.
a116d10 Temporarily disabling the revoke/verify test in the CA.
d87e018 Fixing how the CRL is used for certificate verification.
6c539c0 Fixing puppetca so it uses the :local ca setting.
ebdbe48 Added an Interface class to the CA to model puppetca's usage.
934fbba Making the SSL::Host's destroy method a class method, rather than an instance method.
d4813f1 Adding the last functionality needed for puppetca to use the Indirector.
809fc77 Finishing the interface between the CA and the CRL.
16056a2 Adding inventory support to the new certificate authority.
d498c4a Adding support within the inventory for real certs or Puppet cert wrappers.
67f9d69 Changing the Inventory class to rebuild when the first cert is added, so it's easier to test.
7cca669 Adding a comment to the inventory class.
98db985 Adding an SSl::Inventory class for managing the ssl inventory.
92a7d76 All SSL terminus classes now force the CA information into the right place.
fb56dea Switching the SSL::Host class to return Puppet instances.
f7e0990 Setting the expiration date of certificate objects to the expiry of the actual cert.
71db9b5 Adding integration tests for a lot of the SSL code.
e5c4687 Moving the password file handling into the SSL::Key class.
d8bb81e Moving all of the ca-specific settings to the ca_file terminus classes, rather than the normal :file classes.
cbe5221 Adding SSL::Host-level support for managing the terminus and cache classes. Also, defaulting to the :file terminus for all of the SSL classes.
c5f0eff Fixing the CA so it actually automatically generates its certificate.
3d24b12 The certificate authority now uses a Host instance named 'ca'.
daa8cd5 Changing all of the SSL terminus classes to treat CA files specially.
7d2c05e The 'destroy' method for the ssl_file terminus base class now returns false on missing files, rather than failing.
7555af6 Marking a test as pending, because it's not ready yet.
c19c9d4 Removing all the cases where the ssl host specifies a terminus. Also, getting rid of some metaprogramming that wasn't really helping.
054e4e4 Making the first pass at using requests instead of specifying the terminus class. The individual ssl classes now work, but the ssl host class doesn't yet.
6900f97 Adding a :to_text method that will convert the contained thing to readable human text.
174b9c9 Actually signing the certificates in the CA.
546ac97 Adding the first attempt at managing the certificate revocation list.
c98ad25 Adding a :search method to the ssl_file terminus type and the SSL::Host class.
d184b35 Fixing a failing test that had not been updated from previous coding
b9d6479 We have a basically functional CA -- it can sign requests and return certificates. There's still plenty more work to do, but I'm probably not much more than a day away from redoing puppetca to use this code.
1efed03 Adding tests for the easy bits of the CertificateFactory. I probably am going to skip the tests for the rest, since the code is unlikely to ever change, and it's going to be a royal pain to test.
ee07d0b Adding tests for the certificate serial numbers
dc5c73b The certificate authority is now functional and tested.
a776a12 refactoring the cert request test a bit
7641bd4 This is a first pass at the certificate authority. The tests are basically entirely absent still, but the structure is all there.
0f46815 It looks like all of the new ssl classes for managing keys, certificates, and requests now work, including talking to the certificate authority. Now we just need the authority itself, along with the necessary REST terminii.
00e35bc Adding he last of the indirection classes for the ssl classes, finally including the certificate requests.
8347b06 The certificate and key are now correctly interacting with the existing cert/key store. Certificate requests are not yet handled, nor are the ca-specific collections.
50f3c18 Removing obsolete indirection classes
ec5bdf3 The basics for the certificate and certificate request indirection terminii are done. I need to move most of the test code to a shared behaviour now.
bb87464 Fixing a couple of broken tests.
b0811ad The new SSL classes basically work, but they're not functionally connected to any kind of indirection.
3970818 Finished the certificate request wrapper class.
4ca6fd3 First stage of cert refactoring: Private keys kind of work.
ef7d914 Oops; final fix on the integration test failures resulting from my partial support for ssl in webrick.
0ca0ef6 Fixing whitespace problems.
4640a3d Fixing an integration test of the rest terminus; it was broken by my incomplete cert support in webrick. I just stubbed out the cert usage for now; once all the cert stuff is done we'll need to go back and unstub it.
d738f31 Adding the necessary tests for webrick to have logging and ssl. The tests can't be completed until the certificate work is all done.
b49fb68 Fixing the tests in test/ that were broken as a result of the move to no global resources.
5e78151 Fixing tests that were failing as a result of the merge, including removing some now-obsolete code and tests from the Settings class.
bee9aba Environments are now available as variables in manifests, and specs can be directly executed again.
b225e86 Fixing #1017 -- environment-specific modulepath is no longer ignored.
4ede432 Tidied the man page creation function and created "master" branch man pages
f335dc3 Updated defaults.rb to fix foru error stopping man page creation - links are not as neat as before but puppet.conf.man file will create neatly now.
c751058 Removed remaining elements of old_parse - closing Ticket #990
31e0850 Removed old configuration file behaviour and deprecation warning - closes ticket #990
4165eda More fixes to the testing.
cfda651 Another round of test-fixes toward eliminating global resource references. This should have gotten rid of all of them, and now it's just a question of fixing a few hopefully unrelated failing tests.
488c437 Fixing automatic relationships. I was previously looking them up in the relationship graph, which only stores the vertices, not the resource table.
d8991ab Updated install.rb to product puppet.conf.man page - updating ticket #198
5a0388f Disabled new man page creation support
e5888af Added support for man page creation - requires rst2man.py and writer - closed ticket #198
5bef4a5 Another round of fixes toward making global resources work.
3cc3e0f Lots o' bug-fixes toward getting rid of global resources. We still have about 60 failing tests, but some of them are the failing directory service tests (probably 20 or so), and most are simple fixes to the tests themselves.
b7b11bd Fixing a couple of failing tests
aed51b4 Fixed puppet logcheck issues
7aa79e2 Revert "Fixed documentation for code option in defaults.rb"
f2991a2 Revert "Fixed indentation error in pkgdmg.rb documentation"
754129e Revert "Fixed issue where permissions are incorrectly set on Debian for /var/puppet/run directory"
20628ea Added patch to ext/logcheck/puppet to fix ticket #978
badf977 Fixed indentation error in pkgdmg.rb documentation
e6547f0 Fixed documentation for code option in defaults.rb
594a5a3 Fixed issue where permissions are incorrectly set on Debian for /var/puppet/run directory
9736b3c Updated for 0.24.0
99f9047 tweaking spec language; require Puppet::Network::HTTP class since it is referenced by Puppet::Network::Server
b38f538 Moving $PUPPET/spec/lib/autotest up to $PUPPET/autotest as something has changed and it can't be found otherwise.
e1abfac moving autotest directory to make it possible to run autotest again
0.24.9
======
0dee418 Fixed typo in util.rb
df33cb0 Updated CHANGELOG
a22a088 Updated version to 0.24.9
0aae57f Backport of tmpfile patch from 0.25.2
9a26421 Brought in lutters parse_commands patch and integrated it into the type. This includes reworking the get and match commands as well. This change introduces a few small changes. These are:
916dd60 Fixed rspec gem at version 1.2.2
57b37e5 Add @options to test run call, for compatibility with more recent rspec versions.
0863a79 Adding #2122 - you can specify the node to test with puppet-test
a43137c More RST fixes
843cc6e Fixed RST for functions
6160aaf In order for ReST formatting to work properly, newlines and indentation of doc strings must be retained.
d125937 Added rake ci:all task
c62c193 Updated to version 0.24.8
aa00bde Fixing #1631 - adding /sbin and /usr/sbin to PATH
39deaf3 Fixed #2004 - ssh_authorized_key fails if no target is defined
dcf2bf2 Changelog entries for #1629 and #2004
bbcda1d Fix Bug #1629
69a0f7d Fix #1807 - make Puppet::Util::Package.versioncmp a module function
081021a Fix #1829 - Add puppet function versioncmp to compare versions
2b33f80 Fixed install.rb typo
5ab63cd Updated lib install permissions to 0644
0.24.8
======
02a503f Updated to version 0.24.8
cbc46de Fixing #1631 - adding /sbin and /usr/sbin to PATH
9eb377a Fixed #2004 - ssh_authorized_key fails if no target is defined
1b3fe82 Changelog entries for #1629 and #2004
8a671e5 Fix Bug #1629
ff5b13a Fix #1807 - make Puppet::Util::Package.versioncmp a module function
991f82c Fix #1829 - Add puppet function versioncmp to compare versions
d0bf26e Fixed install.rb typo
4cf7a89 Updated lib install permissions to 0644
2c7e189 Fixes incorrect detail variable in OS X version check, re-patches ralsh to work with Facter values and adds error check for missing password hash files.
73a0757 Fix #1828 - Scope.number? wasn't strict enough and could produce wrong results
0.24.8rc1
=========
84d6637 Fixed #2000 - No default specified for checksum
a3bb201 Fixing change printing when list properties are absent
67fc394 Fixed #2026 - Red Hat ignoring stop method
cf64827 Bring in the documentation changes from the master branch
01bc88c Added a force option to ensure the change is always applied, and call augeas twice to reduce the chance that data is lost
cedeb79 Backport the fix for #1835
cf48ec0 First cut at the not running if augeas does not change any of the underlieing files
9d36b58 Bug 1948: Added patch by jab to support the correct ins syntax. Updated the test cases as well
61661b1 Fixing #1991 - ldap booleans get converted to booleans
d5850dc Refactored a method: extracted about five other methods
1c7c8fe dbfix - fix typo and close another possible inconsistency
c55ac3f Fix #2010 - add protection code for some storeconfig corruption
a790ee3 Further fix to #1910
9577d3a Fixing #2013 - prefetching had a mismatch between type and title
719a8df Fixed to rake tests for reductivelabs build
ac87600 Fixed report reference page
0c16426 Fixing broken 0.24.x tests in test/.
23066c1 Fixing every failing test I can find on the build server.
ec56ddf This script fixes the most common issues with inconsistent storeconfigs database (including duplicate resources record, duplicate param_values records, dangling records...).
c052ff8 Make puppetd --waitforcert option behave as documented:
e2b4062 Adding a performance optimization to the FileCollection.
fa6494b Using the FileCollection where appropriate.
373d505 Adding a FileCollection and a lookup module for it.
0e46786 Fixed #1963 - Failing to read /proc/mounts for selinux kills file downloads
4170238 Fixed #2025 - gentoo service provider handle only default init level
8c010e0 Fixed #1910 - updated logcheck
7504b04 Updated useradd.rb managehome confine to include other RH-like distributions
f07d928 Use Puppet.debug instead of own debug flag
25a3f59 Fixing #558 - File checksums no longer refer to 'nosum'
d758f45 Fixing #1871 once and for all - contents are never printed
c0f4943 Minor fix to launchd tests
24d48e6 Fix #1972 - ActiveRecord fixes resulted in broken tests
446989b Fix spec test for launchd service provider to work with new service status method and add two new status tests.
3ef5849 Fixing a test I broke in commit:"897539e857b0da9145f15648b6aa2ef124ec1a19".
72bd378 Removing a no-longer-valid test.
682dd8b Fixing password validation to support symbols.
44f97aa Only backing up within parsedfile when managing files
04af7b4 Fixing a syntax error in the up2date provider
1070b3c Fixing a test broken by a log demotion
ab84756 Cleaned up variable names to be more sane, clarified error messages and fixed incorrect use of 'value' variable rather than 'member'.
7f41857 Provide dscl -url output support for OS X 10.4 clients using the directoryservice provider.
0bc3c07 Fix launchd service provider so it is backwards compatible with OS X 10.4 as well
2561c8e Updated Augeas type code
7d72186 Removed site from Puppet VIM syntax
1bc7404 Fixed #1831 - Added sprintf function
336b645 Fixed #1830 - Added regsubst function
2a85551 Bug 1948: Add logic and testing for the command parsing logic
2218611 Updated up2date and service confines to add support for Oracle EL and VM
39a8b28 Fixing #1964 - Facts get loaded from plugins
7cf085c Adding tests for Puppet::Indirector::Facts::Facter.loadfacts
70ea39a Adding a post-processor for Nagios names.
4dfa034 Revert "Refixing #1420 - _naginator_name is only used for services"
d5a193a Fixing #1541 - ParsedFile only backs up files once per transaction
53f15b9 Removing the apparently obsolete netinfo filetype.
4e89156 Migrated FileType tests to spec, and fleshed them out a bit.
cc4d658 Bug #1948: Added patch by jab to support the correct ins syntax. Updated the test cases as well
5e35166 Fixing #961 - closing the http connection after every xmlrpc call
af3f3ae Refactoring the XMLRPC::Client error-handling
f0ac3ae Fixed #1959 - Added column protection for environment schema migration
319822a Fixing #1869 - autoloaded files should never leak exceptions
6b0c1b9 Fixing #1543 - Nagios parse errors no longer kill Puppet
7fd5c7e Moving the transaction specs to the right path
efb5cc5 Refixing #1420 - _naginator_name is only used for services
32c2be9 Fixed #1884 - exported defines are collected by the exporting host
0e49159 Cleaning up the AST::Resource code a bit
b22d148 Fix #1691 - Realize fails with array of Resource References
6331bfc Fix #1682 - Resource titles are not flattened as they should
7e036eb Fix #1922 - Functions squash all arguments into a single hash
535fa89 Fixed #1538 - Yumrepo sets permissions wrongly on files in /etc/yum.repos.d
f7b04df Fixed #1936 - Added /* */ support to the vim file
671d73c Prefetching, and thus purging, Nagios resources now works *only* if you use the default configuration file locations.
063871f Adding some basic tests for the Naginator provider base class
897539e Removing a redundant instance prefect call.
012efe3 Fixing #1912 - gid still works with no 'should' value.
a9f34af Fixing the Rakefile to use 'git format-patch'.
db05c00 Fixing #1920 - user passwords no longer allow ':'
aa219e7 Adding README.rst file
1d3f117 Added Reductive Labs build library
f01882d Change the way the tags and params are handled in rails
b7ab54c Add methods to return hash instead of objects to params and tags
5c64435 Rails serialization module to help serialize/unserialize some Puppet Objects
b27fccd Fixed #1852 - Correct behaviour when no SELinux bindings
7403330 Updated Red Hat spec file 0.24.7
0.24.7rc1
=========
84d6637 Fixed #2000 - No default specified for checksum
a3bb201 Fixing change printing when list properties are absent
67fc394 Fixed #2026 - Red Hat ignoring stop method
cf64827 Bring in the documentation changes from the master branch
01bc88c Added a force option to ensure the change is always applied, and call augeas twice to reduce the chance that data is lost
cedeb79 Backport the fix for #1835
cf48ec0 First cut at the not running if augeas does not change any of the underlieing files
9d36b58 Bug 1948: Added patch by jab to support the correct ins syntax. Updated the test cases as well
61661b1 Fixing #1991 - ldap booleans get converted to booleans
d5850dc Refactored a method: extracted about five other methods
1c7c8fe dbfix - fix typo and close another possible inconsistency
c55ac3f Fix #2010 - add protection code for some storeconfig corruption
a790ee3 Further fix to #1910
9577d3a Fixing #2013 - prefetching had a mismatch between type and title
719a8df Fixed to rake tests for reductivelabs build
ac87600 Fixed report reference page
0c16426 Fixing broken 0.24.x tests in test/.
23066c1 Fixing every failing test I can find on the build server.
ec56ddf This script fixes the most common issues with inconsistent storeconfigs database (including duplicate resources record, duplicate param_values records, dangling records...).
c052ff8 Make puppetd --waitforcert option behave as documented:
e2b4062 Adding a performance optimization to the FileCollection.
fa6494b Using the FileCollection where appropriate.
373d505 Adding a FileCollection and a lookup module for it.
0e46786 Fixed #1963 - Failing to read /proc/mounts for selinux kills file downloads
4170238 Fixed #2025 - gentoo service provider handle only default init level
8c010e0 Fixed #1910 - updated logcheck
7504b04 Updated useradd.rb managehome confine to include other RH-like distributions
f07d928 Use Puppet.debug instead of own debug flag
25a3f59 Fixing #558 - File checksums no longer refer to 'nosum'
d758f45 Fixing #1871 once and for all - contents are never printed
c0f4943 Minor fix to launchd tests
24d48e6 Fix #1972 - ActiveRecord fixes resulted in broken tests
446989b Fix spec test for launchd service provider to work with new service status method and add two new status tests.
3ef5849 Fixing a test I broke in commit:"897539e857b0da9145f15648b6aa2ef124ec1a19".
72bd378 Removing a no-longer-valid test.
682dd8b Fixing password validation to support symbols.
44f97aa Only backing up within parsedfile when managing files
04af7b4 Fixing a syntax error in the up2date provider
1070b3c Fixing a test broken by a log demotion
ab84756 Cleaned up variable names to be more sane, clarified error messages and fixed incorrect use of 'value' variable rather than 'member'.
7f41857 Provide dscl -url output support for OS X 10.4 clients using the directoryservice provider.
0bc3c07 Fix launchd service provider so it is backwards compatible with OS X 10.4 as well
2561c8e Updated Augeas type code
7d72186 Removed site from Puppet VIM syntax
1bc7404 Fixed #1831 - Added sprintf function
336b645 Fixed #1830 - Added regsubst function
2a85551 Bug 1948: Add logic and testing for the command parsing logic
2218611 Updated up2date and service confines to add support for Oracle EL and VM
39a8b28 Fixing #1964 - Facts get loaded from plugins
7cf085c Adding tests for Puppet::Indirector::Facts::Facter.loadfacts
70ea39a Adding a post-processor for Nagios names.
4dfa034 Revert "Refixing #1420 - _naginator_name is only used for services"
d5a193a Fixing #1541 - ParsedFile only backs up files once per transaction
53f15b9 Removing the apparently obsolete netinfo filetype.
4e89156 Migrated FileType tests to spec, and fleshed them out a bit.
cc4d658 Bug #1948: Added patch by jab to support the correct ins syntax. Updated the test cases as well
5e35166 Fixing #961 - closing the http connection after every xmlrpc call
af3f3ae Refactoring the XMLRPC::Client error-handling
f0ac3ae Fixed #1959 - Added column protection for environment schema migration
319822a Fixing #1869 - autoloaded files should never leak exceptions
6b0c1b9 Fixing #1543 - Nagios parse errors no longer kill Puppet
7fd5c7e Moving the transaction specs to the right path
efb5cc5 Refixing #1420 - _naginator_name is only used for services
32c2be9 Fixed #1884 - exported defines are collected by the exporting host
0e49159 Cleaning up the AST::Resource code a bit
b22d148 Fix #1691 - Realize fails with array of Resource References
6331bfc Fix #1682 - Resource titles are not flattened as they should
7e036eb Fix #1922 - Functions squash all arguments into a single hash
535fa89 Fixed #1538 - Yumrepo sets permissions wrongly on files in /etc/yum.repos.d
f7b04df Fixed #1936 - Added /* */ support to the vim file
671d73c Prefetching, and thus purging, Nagios resources now works *only* if you use the default configuration file locations.
063871f Adding some basic tests for the Naginator provider base class
897539e Removing a redundant instance prefect call.
012efe3 Fixing #1912 - gid still works with no 'should' value.
a9f34af Fixing the Rakefile to use 'git format-patch'.
db05c00 Fixing #1920 - user passwords no longer allow ':'
aa219e7 Adding README.rst file
1d3f117 Added Reductive Labs build library
f01882d Change the way the tags and params are handled in rails
b7ab54c Add methods to return hash instead of objects to params and tags
5c64435 Rails serialization module to help serialize/unserialize some Puppet Objects
b27fccd Fixed #1852 - Correct behaviour when no SELinux bindings
7403330 Updated Red Hat spec file 0.24.7
8befc18 Updated to version 0.24.7
cf19bd8 Not using a temporary file when locking files for writing.
b966ea0 Modifying the corruption-checking test.
1f34bca Issue 1804 VDev with the same devices should be in sync
6d5a129 Documentation fixes
45144a1 Fixing #1812 (hopefully) - adding read and write locks to yaml.
2385a78 Preparing to fix #1812 - Moving locking code to a module
2961b83 Fix #1815 - puppetdoc --all crash on resource override
e5c36fd Fix ZFS autorequire test
da71ad5 Add a unique name to objects so we can determine uniqueness when read back in
4418b34 Fix launchd service test on non-OSX platforms
4b2bdf9 Fix the spec tests to work on other platforms, do the confine around OS X versions more sanely
544a3e1 remove unnecessary mk_resource_methods call
50ac03a CHANGELOG updates
a0a6d2c Add a unique name to objects so we can determine uniqueness when read back in
68ffd46 Bug #1803 Zfs should auto require the ancestor file systems
7e2da7e Refactor #1802 Use 'zfs get -H -o value' instead of parsing output for value
8616d74 Fixing #1800 - tidy now correctly ignores missing files and directories
6075d10 Fixing #1794 - returning sync when it is already initialized
18fe5c3 Fixing #1750 again - All of the properties and now :ensure check replace?
b22303e Fix rake abort when there is a matching confine
0caa9c5 spec tests for type and provider and some code cleanup to adhere to DRY
0f2fc88 Finished work on rules creation and deletion
ed49153 new better way of doing stdin
05e05bb finished rights flush, working on rules
1e37230 macauthorization type
4ed73ef reset macauthorization tree. Initial checkin of new type/provider
5d32cd9 add NetInfo deprecation notice to user and group providers, make the directoryservice user provider the default, remove default for darwin from NetInfo providers
99ab940 Warn that the NetInfo nameservice provider is deprecated. Use directoryservice instead
c4412ec add some more sanity checks around stdin
7de82c3 add support for stdin to Puppet::Util.execute
edef064 Make ralsh behave more sanely for non-existent objects and property values
9384a4a Added git changelog task
c398db1 Bug #1780 Fixing meaningless test
278bfe8 Fixing mcx test failures (only happened sometimes).
c4812b8 Need to stub out the defaultprovider call for non Mac platforms
b444e43 remove extraneous comments
49d4d01 Trim down the after block clears to try to make the tests work for the build servers
65d6b49 Updated mcx type and provider with comprehensive spec tests.
fd128d6 Fixing a package test to be *much* faster
cdcbc5b Fixing splaytime tests
6a4c0d5 Removing debugging from the "resources" type
0c6a151 Fixing a test that fails depending on test execution order
968f5cc Relicense under GPLv2+
9ab3afb Hopefully fixing #1703 - using a mutex around the sending of the tagmails
3fe9cc7 Fix #1741 - fix some failing tests on some ruby versions.
3570c71 Fix #1788 - allow rspec rake to run only some tests
1b3a7d8 Fixing the AST constant warnings, using a variable instead of a constant
091b8bf Fixing #1785 - selinux tests no longer break other tests
c005dcf Ticket 1780 - Solaris RBAC roles should be autorequired
3eff225 Feature 1696 Add support for branded zones
fa9820b Bug #1778 - Solaris RBAC profiles should maintain order
f6fa4f7 Bug # 1680 Now you can set the hashed passwords on solaris
0a40668 Feature #1783 - Add ZFS support
047e5d0 Handle password when user is created
88edf66 == is not =
a219c88 Solaris doesn't have a native tool to set hashed passwords
9329c95 type/mcx.rb Feature #1026 - MCX Type
83b3a1e Simplify launchd service provider and add tests
65a6074 Fixed #1695 - Solaris 10 zone provider doesn't properly handle unknown zone attributes in newer releases
0171e25 Fixing #1749 - Splay now hopefully behaves "better" for small values.
607958c Fix #1741 - Add inline_template function
cc45c43 Fix #1741 - refactor TemplateWrapper, test for template function
d8c741f Fix #1741 - Puppet::Parser::Functions rmfunctions and unit test
3c4efa7 Fixes #1773 - no longer check for absolute paths
3a39509 make sure only types that have passwords search for the password
a45c6b1 fix bug with numeric uid/gid in directoryservice provider. doc string cleanups
1f52795 Documentation fix for runit provider
81a91a7 Documentation fix for daemontools provider
4f67a7c Fixed #1776 - Trivial fix for gentoo service provider
2764ab4 Rename migration so it's still applied
965c08d Slight denormalisation to store a host's environment as a first class object in the database Fixes: #1392
5742966 Fixing #1743 - defined types get catalogs too.
31ec3e6 Adjusted CI tasks exit codes
3421954 Fixing #1755 - handling fully qualified classes correctly.
a1ac9a5 Added Rake :ci namespace and CI tasks
d978668 Lots of DirectoryService work. New Computer Type. Users now use password hashes. Groups now support setting members as attributes of the group for OS X.
86ce934 launchd service provider
97a8177 Refactoring the thread-safety in Puppet::Util a bit.
78bced1 Fixing #1683 - accessing and changing settings is now thread-safe.
83cebb5 Partially fixing #1772 - fixing selinux tests broken by removal of extraneous 'stat' in :file.
a839fe2 Partially fixing #1772 - fixing tidy code I broke.
5bd27c8 Partially fixing #1772 - broken 'resources' tests.
a3140b2 Manually setting an env var to mark autotest enabled so we see color
bbad983 Removing the included testing gems; you must now install them yourself.
b415848 Fixing #1708 - user groups specified as names are now detected correctly.
9ed382d Fixed #1767 - Minor fix to emacs mode
27a750d Revert "Fixing #1755 - File modes (and other strange properties) will now display correctly"
eb0d32a Fixing #1764 - a property's 'sync' method is never considered a no-op.
e9f858a Refactoring the file/owner property to be simpler and cleaner.
ed4c405 Fixing #1755 - File modes (and other strange properties) will now display correctly in ralsh and generated manifests.
c65f2b5 Fixed #1668 - puppetca can't clean unsigned certs
1ad33cc Fix #1759 - Comparison operator was using string comparison for numbers
c96d250 Fixed #1711 - fileserver test fails due to incorrect mocking
8523a48 Fixed #1751 - Mac OS X DirectoryService nameservice provider support for plist output and password hash fil
d32d7f3 Fixed #1752 - Add an optional argument to Puppet::Util.execute to determine whether stderr and stdout are combined in the output
4396740 Fix the init service type to cope with an array for defpath and if defpath does not exist
3c870d8 Added versionable feature to the RPM provider
f62d04d Fixing broken tests resulting from the fix to #1747
030c791 Moved RRD feature from util/metric.rb to feature/base.rb
dc192b0 Manifest documentation generation
2c05a0a Move function existance test to parser evaluation
064fb00 Add a doc attribute to AST nodes and fill it with the last seen comments
724a6f6 RSpec tests for the doc system (covers AST.doc, lexer and parser)
b8ed667 Fixed #1735 and #1747 - Fixes to confine system
6be5ac8 CHANGELOG updates
0ca5025 Fixed #1718 - Added preseed to apt uninstall and purge
01976ca Include spec directory in packages
c98f7a5 Fixing the provider's confine subsystem so the logs are more useful.
6426a29 Removed extra 'end' from yum.rb
1e81739 Fix bug #1746: Sync SELinux file attributes after file contents created/modified
cebadd9 Fix bug #1681: Add filesystem type check to test for per-file SELinux context support
60455e7 Quiet debug when no default SELinux context found for one of the components
71a9e60 Fixes relating to transition to native SELinux bindings
3a5dcab Refactoring of SELinux functions to use native Ruby SELinux interface
d5e19f1 Fixed #1739 - Added uninstall functionality to yum provider
bf5be00 Fix #1737 - part2 - Fix display of "options"
e032034 Fix #1737 - ssh_authorized_keys should be able to parse options containing commas
e33d087 Fix #1740 - Daemontools and Runit is not ReST compliant
dfc0554 Fixed #1730 - Edited file/ensure.rb docs for clarity
6d7b5ef Fixes #1672 - unsafe crontab handling in Solaris Signed-off-by: Martin Englund <martin@englund.nu>
083077d Fixing the augeas type tests to work when augeas is missing
0a3d34d Fixes #1714 - yumhelper handling with yum 2.2.x is broken
7b70e85 Fixed #1721 - puppet.conf documentation incorrectly lists signals that affect the daemons
781a685 Fixing a test I broke when fixing a reporting bug
f063517 Added unit tests for the augeas type and provider
2d37f09 Fix #1402 - Allow multiline comments
9f30306 Fix #857 - Multiple class of the same name don't append code
649a9e0 Fixed augeas examples in type
56f3be6 Fixed #1710 - Spurious output in test run
4806c51 Fixing #1669 - The dump parameter can now be changed on mounts.
c7ccc4b Fix #1682 - ASTArray should flatten product of evaluation of its children
c906afd Fixing #1667 - regex automatic value documentation is now readable.
9fd1756 Split Augeas up into a provider and a type.
e542f8c Fixed #1692 - k5login fails to set mode when file is created
57e791b Fixing #1660 - Adding specifically supported values for tidy recursion.
42cac73 Fixing #1698 - all logs again show up in the report.
6ab4f1b Fixed #1661 - Type reference: tidy should specify manditory parameters
2459106 Removing all mention of EPM, RPM, or Sun packages.
9ecbd63 Fixed #1104 - Classes and nodes should set $name variables
bc8cdb1 Beginning provider split, need help on the voodoo
6539f55 Updated Red Hat spec file for 0.24.6 and removed conf/debian directory.
cacafeb Added augeas type and feature
0.24.6
======
b2c1149 Updated to version 0.24.6
5ba54d2 Updated to version 0.24.6
22024bc Improve the inline documentation for SELinux types and parameters
f216237 Fixes #1663 - added Symbol check and additional test
81c3b72 Fix SELinux test to succeed when Puppet debug mode is enabled
f7516a7 Fix regression caused by switch to Puppet's execute() functions
c09d0cc Solaris RBAC Attributes
6d05cbc Fix #936 - Allow trailing comma in array definition
ec2b461 Fix #1115 - part2 - fix tests and add all_tags
356d8ca Fixed #1662 - Configuration Reference still references 'section'
b53509b Fixed #1460 - enhance redhat puppetmaster init.d script to easy start puppetmaster as a mongrel cluster
8a4e2e9 Fixed #1663 - Regression relating to facter fact naming from 0.24.5
e6f99f9 Fix #636 - Allow extraneous comma in function argument list
a74ec60 Fixing tests I broke when trying to fix the Providers reference.
d4df361 Use fully qualified paths when calling binaries, adjust chcon call to use Puppet's execute() function.
dedf0cd Setting SELinux contexts with chcon should not dereference symbolic links
7f5ded1 Fixed #1646 - service puppet status does not work as non-root on redhat system
00d5fe4 Fix #1115 - Allow checking tags/classes from ERb templates
f5fb2d3 Fixed #1649 - OS X package creation script should be more selective about cleaning out prior versions
b0fd2e0 Fixing #1647 - puppetdoc's 'providers' report works again.
157c0dd Fix 1642 (always warning) and improve unit tests to cover when to warn and not
65eafb7 lazy load latest package definitions with yumhelper 2.2
eff6ce0 Revert "Added last part of #1633 patch - update to util/metrics.rb"
c5d1a4f Added last part of #1633 patch - update to util/metrics.rb
0fff7d7 Fixing some tests that were broken in 2fba85af
2afbd0d Fixing a test that was failing as a result of the fix to #1491
b0c01da Adding an additional option for the fix in ff36832e, skipping missing cert dirs
aea5582 Removing a gid test for users, since it is a bad test and has mostly been replaced in rspec
65d3040 Fixing a test that was broken in ee579641
b08002e Fixing some tests that were broken in the fix for #1633
2bf0ba5 Fixing a test that was failing because i-have-no-idea
952ebb8 Fixing a test that was failing because of the change to retrieve() in ee579641
a5fe87f Fixing a file source test that was failing because missing sources is now a failure
53b7d42 Fixing the broken tests resulting from the fix for #1551.
5ec6b07 Adding warnings when example groups are skipped.
54abe70 Moving some test/ package tests to rspec integration tests and disabling a gem test that hangs forever for me.
85d3ae0 Cleanup selboolean and selmodule unit tests to pass on non-SELinux systems
a562ce5 Add unit test coverage for Puppet::Util::SELinux and fix problems found by tests
2b4aa0c Fixed #1639 - uninitialized constant Puppet::Type::User::ProviderUseradd
4265825 Fix #1636 - part2 - correct some client errors.
9c31db9 Add failing test for plugin with file and recurse
2853447 Fix several small regressions in plugins mount
2153bae Fixing #1640 - file groups now no longer get set on every run (this was a regression caused by other work I did).
80e5c11 Incremented CHANGELOG to 0.24.6
996ac46 Fix scenario when SELinux support tools exist, but SELinux is disabled
d803096 Add new set of unit tests for selmodule type
a3f34f9 Removal of redundant lines from unit test
307260f Remove old selboolean unit tests and fix permissions on new tests
2ebd34e Rewrote seboolean unit tests to provide better coverage
4df51ea New and improved tests for file type SELinux contexts
253d4df Fix regression when templatedir doesn't exist.
c7a6ef2 Fix #1202 - Collection attribute matching doesn't parse arrays
3281f2b Fixed #1633 - Added support for --detailed-exits to bin/puppet which causes puppet to produce different exit codes depending on whether there were changes or failures in the transaction.
0b1e60f Adding an array indexer method to Puppet::Util::Metric as requested in #1633.
765db30 Adding partial spec tests for Puppet::Util::Metric.
fb14e91 Fixed #1473 - Rescue Timeout::Error in xmlrpc clients
7275d7c Fxied #1354 - yum provider problems with RHEL 3
0c297be Fix #1109 - allow empty if or else branches
5268487 Fixed documentation, typo and added CHANGELOG entry
990e8e3 Fix #1530: Correctly parse ssh type 1 keys
06edac4 Fixed additional environments tests
79bb1f2 Rspec Tests for #381. Moved part of the old resource reference tests to rspec.
750e9ab Fix #381 - Allow multiple resource overrides or references
782181e Minor test fix for #1614
614326a Fixing #1098 - Multiline strings now correctly increment the line count
1c6d57e Doing some simple refactorings on Puppet::Log
a774443 Fixing #1089 - Log messages are now tagged with the log level, making it easier to match messages in the 'tagmail' report.
db7f108 Adding rspec tests for the Puppet::Util::Log class.
d2c8998 Fixed #981 - Removed 'Adding aliases' info message
d098a90 Fix failing tests dependent on /etc/user_attr file existing
6bcfd9f Fixing #947 - pluginsync no longer fails poorly when no plugins exist
67136f1 Fixing the Node class to no longer validate environments since #1614 removed that validation.
a4110a3 Add SELinux context reset after file writes in Puppet::Util::FileType
250239e Add new support for :selrange SELinux file property
c831482 Add detected defaults for existing SELinux file properties
772e9b2 Refactor SELinux commands to utility module
8153181 Clean up of SELinux rspec tests so all pass
e77ddc1 Merged fsweetser's selinux patch against HEAD
7272d49 Fixed #1613 - The client environment will be substituted when looking up settings.
1a9b567 Fixing #1614 - Environments no longer have to be listed out.
397c841 Fixed #1628 - Changed node search to use certname rather than Facter hostname
9d174c4 Updated puppet binary documentation
6a0b334 Fixed error message typo
655f378 Adding a rake task for sending emails to the dev list
d39bab9 Fixing package provider tests to use the new Transaction::Change interface
e32256a Migrating the apt and dpkg tests to rspec.
ddda80a Update change log with RBAC roles
d1abb86 Add role support to user type and an implemention
2fba85a Some small clarifying refactors and change to objectadd to allow subclasses of with a uid not need to be a single class us use modify
4a863c3 Adding user_attr util to parse attributes on solaris
93f952a Fixed #1586 - Specifying "fully qualified" package names in Gentoo
8620775 Fixed #791 - You should now be able to create and find a user/group in one transaction.
63ad845 Refactoring and adding tests to the file group property.
7da4152 Modified the group and zone resource types to no longer call 'currentpropvalues' as a means of setting all values to absent. There should be no behaviour change from this change.
ee57964 Modified the behaviour of resource-level 'retrieve' -- it only calls 'retrieve' on each property if the resource exists.
0fb4693 Updating changelog for #1622
2afc4f5 Adding tests for the user retrieve method
679fede Removing commented code from the user type from about 2005
2480654 The Netinfo and DirectoryService providers can now create user and group simultaneously.
4c998fe Fixing #1622 - The user type only looks up groups when necessary.
6bc56ae Aliasing the rspec 'should' method to 'must' so it does not conflict with the RAL 'should' method.
b9c75cd Rewriting the user tests, in preparation for enhancing them
99de920 Fixed #1620 - Add 'sles' to Puppet confines when 'suse' is used
4cf9710 Add parser for arbitrary expressions
cfa230a Add arithmetic operators to AST
850e0ba Add not operator to AST
9cdecfe Add comparison operators (< > == != <= >=) to AST
8372dc4 Add boolean operators to AST
e6698c2 Add warning and forcibly set to :md5 fixing #1564
af8c706 Fix metadata class for cases when checksum_type set
860bdb1 Fixed #1603 - Added support for running Puppet inside a Rack application
b2f0d87 Fix ticket 1596 in new fileset code, use tmpdir in fileserver tests.
a30ecf2 Make fileserver use fileset for recursion and handle dangling links by ignoring them fixing #1544
3b80763 Add tests for FileServer::Mount list for #1544
3749267 Fixed #1610 - Raise "Filebucketed" messages to Notice priority
f792b64 Added a number of confines to package providers
074abd4 Fixed #1609 - Added confines for the Gentoo, FreeBSD and SMF (Solaris) service providers
2da6d19 Fixed #1608 - Added ubuntu to defaultfor for apt provider
aa629ec Fixed #1607 - Added ubuntu to defaultfor for Debian service provider
774c0f9 Fixed #1588 - Fixed puppetca --clean --all
98e79f8 Fixed #1472 -- defined, exported resources in the current compile now get expanded correctly.
0040bc8 Fixed #1045 - Multiple metaparams all get added to resources.
8d5ded0 Removing some code in Parameter that is unnecessary.
5fbdc49 Fixed #1595 - Internally, Property#retrieve is no longer called when no 'should' value is available for a resource.
c16a5ae Only apply splay the first run
27f0c7d fix failing hpux user specs
7a3a38f Add rspec unit test for the append operator
16793d2 Add an append (+=) variable operator:
7f8abbd Bug #1550 - Rework to avoid regressing rspec tests, add new rspec tests for templatedir as a path
0905734 Allow a templatedir to be colon separated.
11b0848 Fixed #1500 - puppetrun host regression
3b1d6e2 Fixed #1579 and #1580 - errors in the Puppet RPM spec file
77f4fb6 Fixed #1521 -- ldap user and group are now used with the default connection when available.
a1a670b Fixed #1572 -- file purging now fails if remote sources do not exist.
dd4f654 Fixing #1576 - moving all of the Puppet::Type code back into type.rb.
923fd89 Fixed issues with file descriptors leaking into subprocesses
cab5d85 Fixed #1571 - Puppet::Util::binary returns incorrect results
a7306e1 Fixed #1553 - Puppet and Facter cannot both install the plist module into two different locations
758505b Fixed #1568 - createpackage.sh
7ce902d Adjusted hpuxuseradd user provider to confine to HP-UX and fixed HP-UX user provider path regression
8f1336f Fixed #1566 - changed password property of the user type
d4d3213 Fixed debug messages in package type - thanks to Todd Zullinger for this fix
b88df5a Sync with latest Fedora/EPEL specfile
0705dfb Fixes #1455 - Adds HP-UX support for user type
e15d316 Fixes #1551 puppetmaster.freshness xmlrpc call returns incorrect type
8fe0338 Fixes #1554 - Fix exception for undefined hostname
81cc9bf Fixed #1533 - changed permissions for man directory
41dc1fa Runit service provider
aae0793 Daemontools service provider
29ae879 Fixes tests broken by 95aa085
b50e718 Fixed #1488 - Moved individual functions out of functions.rb into the lib/puppet/parser/functions directory. New functions should be created in this directory.
5fb5091 Fixed #1457 - case insensitive match for error
ded94f7 Removed spec color option for buildbot
415663b Added simple rake task for running unit tests
557be9d Added spec Rake task
0d118a5 Fix leaking LoadedFile when adding templates to be watched
67387e2 Fixed #1506 - Removed storeconfig duplicate indexes
7accb89 id column is autogenerated by rails as a primary key, there is no need to create an additional index on this column. This changeset contains the new schema and a migration.
c5fb092 Removed reference to namespaces from --genconfig documentation
1729de1 Updates to ext/puppetlast to support multiple hosts
b6609ee Fixed #1508 - Add HP-UX package provider.
3e482a2 Updating the authors list for the gem spec
2ec4e29 Fix #1502 - abysmal storeconfig performance - part2
9272df4 Fix #1052 - abysmal storeconfig performance - part1
f48a0ae Fix #1510 - storeconfig fails with rails 2.1
b1ad596 Add the -P/--ping option to puppetrun, fixes #1501
6676b6b Fixes #1274 - allow class names to start with numbers
d02f95c Fixed #1394 - Added stored configuration clearing script to /ext
fb8cc53 Fixed #1442 - replaced use of Facter for report titling with certname
18dda20 Fixed $1456 - add proxy configuration to yum repo
ab4cb6a Fixing #1447 -- Replacing Puppet::PackageError with Puppet::Error.
8a0cb16 Added tests for TemplateWrapper's use of Scope#to_hash.
3ae7eca Fixing an ldap connectivity test
d3393b4 Added CHANEGLOG entry for removal of interface type
bfcdfe8 fix terrible error with overwriting permissions
0147570 Fixed #1457 - removed confine warning
fecdfbc A working script to create an OS X pkg out of the Puppet repository
6a2e71d Fixed #1441 - Updated console colours
404450a Add testing for the changes to resolve redmine #1427, where Kernel methods shadow variables that the puppet template should otherwise see. Specific changes:
03c76de Expose all puppet variables as instance member variables of the template wrapper. This helps resolve redmine #1427, by providing a safe mechanism to access variables.
13069ec Ensure that we consistently use either string #{} interpolation or String.% interpolation, not both, to avoid issues where a #{} interpolated value contains a % character.
469c5fe Feature #1476: Allow specification of --bindir --sbindir --sitelibdir --mandir --destdir in install.rb
2a3d195 Specs for yaml indirector .search - I'm still learning!
c97389d Made puppetlast work on 0.24.5 by using the YAML indirector
5c53617 Added a search method to the YAML indirector.
482489a Revert "Fixing puppetlast to make it work with 0.24.5 / 0.25."
0bbac8d Fixes #1417 - whitespace in ssh_auth_key provider
a772110 Sync with latest Fedora/EPEL specfile
97987a7 Feature #1241 : Improve performance of group lookups
fe99828 Bug #1448: Puppet CA incorrectly writes out all certs to inventory .txt on each certificate signing
971af69 Fixing puppetlast to make it work with 0.24.5 / 0.25.
d91d806 Updating the authors list for the gem spec
0.24.5
======
ce964ec Updated to version 0.24.5
a7df4eb Updated to version 0.24.5
4dffaf3 Reverting the version so my release process works
aac7dd1 Incremented versions
bfcd626 Fixes #1445 and #1426
8f5800f Fixes #1445 and #1426
ff36832 Fixing the renaming code to skip missing directories.
8c2478b Fixing puppet_module -- it needed the same node interface change.
d9aa5ab Fixing a cert test to pass on Darwin.
686ba4d Revert "Merging fsweetser's selinux patch against 0.24.4"
f16da42 Merging fsweetser's selinux patch against 0.24.4
a47fed4 'Fix' broken tests related to missing source raising Issue 1437 In two cases, I removed the assertion that caused the failure. In one case, I changed the assertion to expect an exception.
238b8d7 Fixing #1438 -- mongrel and module tests now pass.
ebb219e Fixed all of the fileserving termini so they use indirection requests.
d8937ac You can now select the encoding format when transferring the catalog, with 'yaml' still being the default but 'marshal' being an option. This is because testing has shown drastic performance differences between the two, with up to 70% of compile time being spent in YAML code. Use the 'catalog_format' setting to choose your format, and the setting must be set on the client.
a0fa09f Revert "Fixed #1201 - all external node attributes are converted to strings."
8f8ce60 Fixed #1431 - Provider confines must now specify similar tests in one call.
7fa7251 The mongrel-related tests now run without mongrel.
bdbd992 Updated /spec/unit/rails.rb test
de6aec6 Fix Ticket 1426 - services on redhat are restarted again
0a0fcaf Fixed #1414 - Return code from waitpid now right shifted 8 bits
61b9bcd Added Changelog entry for new auth_key type
65b9869 Further moves from the examples directory and ext directory
4ce7159 Fail instead of log when rescuing remote file connections
4c5293b Fix #1409, Move path expansion from the type into the provider
8043655 Fixing #1408 - --loadclasses works again.
605d760 Moved debian to conf and updated examples directory
d25c2b2 Fixed #1407 - allowdupe is now a boolean group parameter.
9eb9aff Fixed #1368 - updated Red Hat init scripts
c7dc73f Fixing the user ldap provider tests
edf99c5 Added message referencing ReductveLabs build library
6ff9246 Fixed #1396 - Added sha1 function from DavidS to core
19b76c7 Fixing #1401 - integration tests now work regardless of the yamldir.
667fac1 Fixed #1226 - Gems can now specify source repositories.
21d4957 Correct whitespace
4762b52 Moving the gem test to the non-ral directory
71f4b02 Importing Sam Quigley's work to enhance gem support for sources.
c751e4e Fixed #1272 - ldap group names will be converted to GIDs.
0922c3b Fixed #1399 - the ldap user provider knows it can manage passwords.
196494a Fixed #1231 - Exceptions during startup should now be clear.
9d69b3f Testing and simplifying the Transaction::Change#backward method.
61ec332 Removing the Transaction::Change#transaction accessor.
2863df2 Refactoring the Transaction::Event class.
a37a784 Adding tests for the Transaction::Event class
31ffeab Adding tests to the Transaction::Change class.
8865bdf file object creation should fail if source is not present
73c06c0 Renaming Puppet::Event to Puppet::Transaction::Event
84b5665 Updated test/ral/type/sshkey.rb test
5ef8979 Removed debugging from lib/puppet/util/ldap/connection.rb
6124c69 Renaming the Puppet::PropertyChange class to Puppet::Transaction::Change.
ba12d30 Fixed #1232 - the rundir no longer specifies a user/group, and there are now client- and server-specific yaml directories.
be169da Removing all of the code related to the interface type.
04ecb74 Doing what I can to fix #1128, but just in preparation for removing 'interface'.
2279acd Adding changes to config print that were missed in fix for 1183
a87885a Fixing the "describe" in the redhat interface specs
bd3f8e3 Fixed 1240 - puppet will function more like puppetd if graphing or reporting are enabled.
7a6ae29 Add a missing test for exercising the last untested line of lib/puppet/type/ssh_authorized_key.rb
731d0f2 Minor documentation updates for ssh_authorized_key type
c825c99 Fixing the ldap node terminus to merge facts with the right name.
4b6b22e Adding logging when a node's facts can't be found
daf0d9d Backporting a test that was failing in master, and fixing it
38540d5 Fixing the ldap node integration test so it cleans up
e03c1be Fixing #1382 - existing uppercase certs, keys, et al will be renamed.
5156230 Use generate instead of autorequire in the ssh_authorized_key type based on Luke's comments
d3a8125 Fixed #1006 - puppetrun --class works again. I added the class membership testing to the Ldap node terminus, and added tests,
c1e010f Fixing the Node::Ldap.search method to use an indirection request.
4d22a95 Switching the ldap terminus to use Util::Ldap::Connection.
b47d4e1 Added a 'search' method to the ldap node terminus.
a1d1abd Adding an 'instance' class method to ldap connections.
ee9d002 Fixed #1114 - Facts in plugin directories should now be autoloaded, as long as you're using Facter 1.5.
f1d5903 Fixing #1388 - the package test no longer uses 'require'.
8c5c949 ssh_authorized_key: autorequire, default permissions and cleanup
5a283d6 Fixing #1374 - Using Puppet::Type.type() in tests
17afb8a Fixes #1195 - Updated Gentoo init scripts
00182ff Fixed #707 - special '@reboot'-style cron jobs work again.
c83b23d Updated CHANGELOG for two missed commits
2380fcd Fixed #1012 - templates in the templatedir are preferred to module templates.
4d95364 Fixed #1221 - aliases to titles now work for resources.
24ca81f Fixed #1360 -- allowdupe works with groups again.
955a8ff Removed test/util/loadedfile.rb tests which fixes #1370
9c1ab14 Fixed #1371 - Updated bin/puppet to use Node.find
aedfa2b Fixed #1369 - the init service provider now supports HP-UX.
422dea0 issue 1183
d3a4d9a Updated Rakefile fixes #1367
5f600dd Fixing #1168 (for 0.24.x) -- automatically downcasing the fqdn. Also requiring that passed in certnames be downcased; the setting system isn't currently flexible enough to automatically downcase it for the user.
ac7f596 Fixed #1201 - all external node attributes are converted to strings.
6658463 Updating the changelog for the changes to node lookups.
1f19453 Removing the Node.find_by_name method.
51e1ba8 The LDAP Node terminus now searches for the fqdn, short name, and default.
fb4e843 Refactoring the 'find' method a bit in the LDAP Node terminus.
317af36 Removing the now-obsolete Node.node_facts method.
b7bd427 Converting the Node.node_names class method into an instance method.
75c94e3 Removing an obsolete, unimplemented test
98e38a6 Adds support for keepconfig for the dpkg provider fixes #234
4d70449 Fix bug in test, add more specs and small refactor
86f8ff4 Removed the unless condition in query, because the issue is a stale cached value and added comments that query will now always do so.
4539b1c Issue 1215
7b2c310 Adding another note about the save_object stub.
d816614 Fixing #1362 -- I had previously removed a stub point needed for testing.
9b1301c Removing a duplicate call left over from debugging
087480b Replacing all two-space indents with four-space
3980323 Adding ruby interpreter lines to the tests missing them.
9fe2b03 Adding execute bits to every test currently missing them.
fb5f09b Fixing how the Indirector::Request sets its options.
4b29a5e Fixing how the indirection tests for whether the request has node info.
6764af3 Change description of spec to make baby jesus happy
946081b Try again
bdc578a Applying the fixes recommended by David Schmitt to the inline documentation of the ResourceTemplate class.
886c984 Updating the docs for ResourceTemplate.
29c840a Adding a class for using templates directly within resources (i.e., client-side templates). This would really only be used for composite resources that pass the results of the template on to generated resources.
1205881 The mongrel and webrick REST handlers now extract certificate information.
e8044f9 Adding to the indirection request support for authentication information.
dbd9b40 Updated fix for ticket #1271
cf3b98e Applied patch for ticket #1271
9943da6 Further Emacs puppet-mode fixes
3c2e69f Fixed Rakefile to install non-.rb files to fix #1266
ad3803f Fixes for install.rb running of tests that fixes #1267
65c1889 Fixing #1242 -- lack of storeconfigs only produces warning, not exception.
8a22b59 Fixing #1265 -- the ca/client tests now all pass again.
02411f5 Always using the cert name to store yaml files, which fixes #1178.
89100c4 Moving the majority of the pkgdmg docs to the wiki, fixing #1264.
9decf35 Put function in ticket #311 in correct location
6c3e7e1 Reverted function - "Added cron random function fixing ticket #311"
c173264 Refactoring warnings.rb for tests.
e6837a4 Fixing an inaccurate test so the tests will run correctly in all branches.
054a811 Removing extra debugging
bdcf5db Fixing tests that are broken when running as root under OSX 10.5
d55a755 Added warnings test and cleaning up trailing whitespace.
c0f78b4 Fixed a bug in my tests which caused them to fail when run against the master branch.
d54338f Added cron random function fixing ticket #311
6ea494f Pushed patch fixing #1235
c370104 Fixing the node/catalog so that it can convert from parser catalogs to RAL catalogs.
bd51a53 Fixing transaction support for prefetching generated resources.
4434072 The ldap user/group providers now work when no users/groups are in ldap yet.
419f244 Adding support for settings within the existing Facter provider confines.
3e13bd5 Intermediate commit so I can move on to other things.
ee4be4f Removing an unused file. Closes #1229.
b8ce6a1 Mocking Facter in an integration test, so it works with no networking
77ee4ec Refactoring how the provider confine tests work, again.
0820819 Minor cosmetic changes to cleanup some style elements and get rid of some cruft.
6a6a1d9 Another refactor based on feedback from Luke. This includes adding an accessor for @@state to make testing a bit cleaner.
ee04129 Refactored tests based on feedback from Luke.
d7f25ff Rewritten tests for Puppet::Util::Storage.
c5da401 Add unit tests for Puppet::Util::Storage
8008bbc Modified the 'factpath' setting to automatically configure Facter to load facts there if a new enough version of Facter is used.
a02c6bb Fixing a mock in the redhat interface test.
390db80 Updated puppetd documentation which fixes ticket #1227
2d6a914 Fix for latest method in rpm provider (fixes #1224)
38545d9 Crontab provider: fix a parse error when a line begins with a space character
a1409d7 Moving all confine code out of the Provider class, and fixing #1197.
995991d Switching the Provider class to use the new Confiner class.
c9757a6 Moving the 'confine' handling to separate classes.
ac79a79 Duh, fixing all of the paths being loaded for spec in the moved tests.
d02334f Moving all tests that are in 'ral' up a level.
e7bef08 Fixing the user test.
158d3df Added the ability to add arbitrary attributes to ldap.
83ef1b0 Fix for #1219
b500689 adding more autotest docs
c61fc02 Adding autotest info to the ext/ directory.
59b9958 Correcting whitespace in the templatewrapper code.
49dde11 Adding has_variable? support, fixing ticket #1177
d8cc1c5 adding execute bits to tests
5e2a4b5 updating the changelog for the ldap providers
17e8158 Adding ldap providers for the user and group type.
c56e9a6 Fixing another test that wrote to ~
954aad4 Fix Emacs mode indentation of multiple nested blocks
f52e343 Enhancements to syntax highlighting and indentation for Emacs
9bf21a6 Use our own count-matches for Emacs 21 compatibility
20e60b1 Applying patch by martin to fix #1207.
270c007 Clarifying the exception when there's a syntax error but a valid parser.
f3fa589 Fixing a test that wrote to ~.
ae842ea Fix for urpmi provider that fixes #1217
da4cdd2 Fix for ticket #1218 - changed to appropriate variable name
88ec3d8 Cosmetic fix
67dc261 Removed "none" as a valid type attribute value, it was useless anyway
db8a46c New native ssh_authorized_key type
2b185af Add values for dump parameter for the mount type closing #1212
69fc802 Update to man pages, fix to ralsh help text and fix for #1211
c57e194 Fixing an error message to be more clear
5a2bbad fix bindir/sbindir defaults on OS X 10.5
fff6ad9 Fix for ticket #1209
b2a3db9 Fixed #1196 - added /sbin/service support for the redhat service provider + some doco fixes
62ca726 Fixed some tests broken by #1176
82b9f61 Added puppetlast script to ext directory
a35450b Pushed patch for #1176 - configtimeout fix
57fd88b Pushed patch for ticket #1191 - adding globbing support to ports provider
b5640a1 Pushed patch for ticket #1187 - freebsd pkg_add support
0a5d8a6 Fixed #1195 - support for gentoo openrc
4599791 Pushed schema patch for #1193
eac14f6 Fixed #1189 and added support for --all to puppetca --clean
d9846fc Fixishing some pending tests, including filling in the connection information.
cb617f2 Making the changes necessary to get the REST support to work with the current state of the indirection work, including using a request object and an expiration date.
a6a397b The 'destroy' method in the indirection now returns the results of destroying, so they can return true or false.
04aba52 fill out specs for network_* methods; refactor lowest-level network hooks
a0804ae adding rest_connection_details helper to Indirector::REST -- will need to be overridden to lookup the real connection details
aed1375 make sure unit indirector specs are working with #save; fill out network_put pending specs
75bf05d removed a debugging helper from the Indirector::Rest#save method
9187a34 updating mongrel/webrick unit tests to match integration-tested version of REST save functionality
93bc1a9 adding REST save support, with integration tests. A handful of unit tests in that area now need to be updated.
99b295b disabling caching for Puppet::Indirector::Indirection as it was causing hella problems with testing save without caching; judging my luke's blog this is going to be rewritten somehow anyway
1befd1d work-in-progress; playing with refactoring network_* methods inside Indirector::REST
f28f20b Added support for destroy/DELETE over REST (including units & integrations on both webrick & mongrel).
0797440 updating search integration specs to include webrick
e8caf13 making search work over REST, w/ unit & integration specs
b750482 unit specs and implementation for Indirector::REST#search method
a7f2dd4 placeholders for integration specs on final REST methods
cebb677 ensure that we only run the mongrel specs when mongrel is available as a feature
dab9deb bringing Indirector::REST specs to mongrel-land as well.
1e0f19b Make mongrel happy like WEBrick.
d24c03c exceptions on remote end now properly passed to local end via REST and re-raised (integration-tested)
7a73434 Much larger commit than I would like to land at once. This is all REST-related code. Two specs are failing related to how Mongrel is initialized for REST; will fix those shortly.
a1c4579 a trivial integration test to test whether the RESTful indirection terminus has a remote shot at working; will need to be upgraded to actually be useful
7d51146 fixing Puppet::Node::REST class name to work with autoloader inflection (Puppet::Node::Rest), so we can do Puppet::Node.terminus_class = :rest
e86fde2 This is the first version where mongrel and webrick are reliably startable and stoppable via Puppet::Network::Server.
c2f8c69 the indirector will not serve xmlrpc (this is the responsibility of the legacy networking code; it was a mistake to include stubbed support for it in the new code); removing
13c40e9 removing obsolete TODO comment
2cdd0f8 puppet-compliant indentation
b49fd49 Resources now return the 'should' value for properties from the [] accessor method (they previously threw an exception when this method was used with properties). This shouldn't have any affect functionally; it just makes the method equivalent to 'should' for properties, but it works for all attribute types now.
4aaad26 Modified the 'master' handler to use the Catalog class to compile node configurations, rather than using the Configuration handler, which was never used directly. I removed the Configuration handler as a result.
2925ad1 Fixed #1184 -- definitions now autoload correctly all of the time.
376628d Removed the code from the client that tries to avoid recompiling the catalog. The client will now always recompile, assuming it can reach the server. It will still use the cached config if there's a failure.
3718b64 Fixing #1173 -- classes and definitions can now have the same name as a directory with no failures.
d91b6d8 Fixing #1173 -- classes and definitions can now have the same name as a directory with no failures.
738889b Fixing the expire method (it wasn't using a request internally), and fixing the Facts class so it auto-expires any associated cached nodes when facts are saved.
f285f1a Moved the request creation into the Indirection class instead of the Indirector module. Also, added an 'expire' method to the indirector, so there's an easy way to expire cached instances.
d420701 Making the log messages around caching better.
d82ac98 Fixing the executables to use the new indirection api.
7774d9c Ported the rest of the indirection terminuses over to expecting requests instead of having a random interface.
bf728d2 Intermediate commit.
644d6ba Fixing some tests that were failing because new base types were added to Naginator, but no new related resource types were added.
768315b Adding the ability for indirection requests to be created with instances instead of just keys.
38f0f48 Fixing an errant comment
69a321f Fixing the tests that were failing because of the use of the indirection request object.
f9881ed Adding a Request class to the Indirection layer. This class is currently only used internally by the Indirection instances, but I expect that I will soon be pushing it to all of the terminus types.
4032a27 Fixing the integration tests related to the destroy fix. Yay.
0bd5799 Fixing one other test that was failing because of the change to Indirection#destroy.
941177a Changing how destroy works, just a bit -- it now accepts the name of the instance to be destroyed, rather than the instance itself.
c6729d1 Reworking the caching layer to use TTLs instead of versions based on timestamps. This just modifies the indirection class itself, there is still some work to do to remove version code from other classes.
8e1e06f Removing unused code from the file_serving/metadata class.
1458123 Adding an envelope module to handle indirected instance expiration.
bd858df Changing the default environment to production.
80f8b80 Adding validation to the user type to confirm that the group list does not contain any commas. This seems to be a common problem.
92765ea Making a test executable
7295626 Used stubs to decouple our code behavior from the behavior of the underlying filesystem, as well as removing the need to sleep (which caused the tests to take a long time).
911c7fb Additional fix for emacs syntax for ticket #1160
c13486e Revert "Additional fix to emacs for ticket #1160"
bb65226 Additional fix to emacs for ticket #1160
6f1c469 Extend workaround from 56aad69f8cdf8b0b08fdb7985014986223fa4455 to not only fix UIDs but also GIDs
e621985 Changed some non-standard Ruby locations to env ruby shebangs
2036d22 Fixes debian service enabled/disable issue as detailed in #1161.
1c02749 Committed patch from #1160
335972e Pushed patch to fix #1174
6f32e95 Adding the report reference back; I don't really know why I removed it, since the information in it isn't anywhere else.
f927b97 Updates to rrdgraph documentation
e51d05c Better fix for #1020
4a39d64 Revert "Added updated fix for #1020"
2cac600 Fixed duplicate oid for parentnode and environment in schema - addresses #1170
eae5cee Fixing a duplicate word in the mount docs
4f8df98 Added updated fix for #1020
aa830b9 Adding 0.24.4 header to the changelog
4c63b69 Add a bunch of directives, allows a full parse of stanford's huge nagios config Also reformatted a bit
9d30b26 Fixes #1148 - replaces #!/usr/bin/ruby with #!/usr/bin/env ruby.
874a02f Added check_puppet.rb Nagios check plugin (See #1162)
491a696 I think this will include the man pages in the build but overall the Rakefile needs a rewrite
9cf7150 Added some more tests for loadedfile, based off the old unit tests.
077312a Added rspec tests for loadedfile
0.24.4
======
3a8053a Updated to version 0.24.4
d3e4ed7 Updated to version 0.24.4
55a9009 Pass source to pkg_add via the PKG_PATH environment variable if
6a53519 Fixing #571 -- provider suitability is now checked at resource evaluation time, rather than resource instantiation time. This means that you don't catch your "errors" as early, but it also means you should be able to realistically configure a whole host in one run.
528bbf1 Fixing a couple of tests.
017f673 Moved the configuration of the Node cache to the puppetmasterd executable, since it otherwise causes caches to be used in all cases, which we don't want (e.g., bin/puppet was using them).
bd3f6ec Disabled man page creation by default and updated CHANGELOG
4bfc4ef Modifying the way ensure is handled so that it supports having it be a parameter. This is only useful if you want a composite resource that just generates other resources and passes the value on.
d93e1b4 Fixing #1138 -- the yamldir is automatically created by the server now that it's in the :puppetmasterd section rather than a separate :yaml section.
273c7ec Disabling http keep-alive as a means of preventing #1010. There is now a constant in Puppet::Network::HttpPool that will disable or enable this feature, but note that we determined that it can cause corruption, especially in file serving (but it's client-side corruption).
6aa6fdb Applying patch by Ryan McBride to fix OpenBSD package matching. The actual problem was caused by the fix to #1001.
5a31959 Added man pages and man page creation logic to install.rb
e5b16b2 Ported #198 man page creation functionality to 0.24.x branch
18320b8 Found all instances of methods where split() is used without any local variables and added a local variable -- see http://snurl.com/21zf8. My own testing showed that this caused memory growth to level off at a reasonable level. Note that the link above says the problem is only with class methods, but my own testing showed that it's any method that meets these criteria. This is not a functional change, but should hopefully be the last nail in the coffin of #1131.
f6325dc Found an array that leaked pretty quickly between reparsing files, thanks to work by Adam Jacob and Arjuna Christenson (the finding, not the leak). I'm going to act like this fixes #1131, at least for now, but I doubt it does, since that shows general memory growth over time, whereas the leak here should go away as soon as files are reparsed (because the parser is holding the reference to the leaking array).
25b81b3 Fixing a test I broke with my fix to #1147
4f400d4 Fixed #1147: Cached nodes are correctly considered out of date if the node facts have been updated (thus causing node facts to again be available in manifests, for those cases where they were not).
54bedb2 tweak the (already applied) patch in 388cf7c3df7ce26e953949ed6fe63d76cbbb3691 to resolve #1137; also, add tests which detect the problem.
a240969 Applying patch by wyvern to fix #1142.
e00065a * puppet/ext/emacs/puppet-mode.el (puppet-indent-line): Clean up the code somewhat after commit 738d275f41f3eaf015800021dd2dfe6c42a1ae79, as promised.
5f3ed8d * puppet/ext/emacs/puppet-mode.el (puppet-indent-line): Be more sophisticated about what we do at the beginning of the buffer, so that the first expression after an block-opening statement that happens to begin at the beginning of the buffer gets indented correctly. This may need some cleanup, but I wanted to get the correct behavior committed first.
d1d408c Fix bug mentioned in commit f814e23eab140ad01df4a4a3b187fcbf20da02be:
7514057 * ext/emacs/puppet-mode.el (puppet-comment-line-p, puppet-in-array): New helper functions. (puppet-indent-line): Rewrite to handle three more situations: indent elements in an array, indent single-line blocks, and ignore previous comment content when indenting non-comment lines.
40a389a * ext/emacs/puppet-mode.el: Untabify, in preparation for substantive changes.
0c45a5a Adding another commit for #1136 -- Consolidated the setting of the loglevel and destination to just one call, rather than the multiple calls that remained.
4ce1d37 Fixed ports documentation error
c75cc42 Added more detail about the requirement for ruby-libshadow for useradd password management
1dc6dc2 Final fix to #1136 - further changes to --test setting
e714156 Second fix to #1136 - fixed --test problem
2155fe1 Fix for ticket #1136 --verbose cancels out --debug
4cc18ed Applied patch in #1134
2795ba4 fixing another failing test
a40e9b7 Fixing some tests that only failed under certain circumstances (mostly, when loaded with other files, or when loaded from rake or autotest rather than separately).
7d35ae8 Refactoring how the catalog creation handles errors. Previously, if there were an error creating a resource, the error would propagate leaving any previously created resources still in memory.
1b3c85b Removing extra debugging
2d90468 Fixing a unit test for node integration
e81fc58 Settings now (again?) do not use a section more than once, which should make the system a bit more efficient.
fca467d Removing explicit requires of types and providers, because they were conflicting with Puppet's autoloading. This is clearly a sign that our autoloading is silly, if Ruby's own loading easily makes it unhappy.
34129d9 Removing obsolete code from the fileserving handler. This was obsoleted in 0.24.2.
f62eec8 updating resource references in the docs
d0554db Hopefully *finally* fixed the "already being managed" problem (#1036). The problem only cropped up if there was a failure when trying to manage the system -- this would cause the setting-based resources not to get cleaned up.
13c6de3 Adding a rake taks for updating the trac docs
0.24.3
======
0e26a07 Updated to version 0.24.3
990638c Updated to version 0.24.3
18ed28b Updating changelog for 0.24.3
ab72048 Removing a Settings.use that is unnecessary
bba0b43 Downgrading the "Using cache" message from the indirection to debug
1dc0e24 Modified the ldap node terminus to also use the facts version as the version for a node, which should similarly encourage the use of the yaml cache. (Related to #1130)
4a45a1d Caching node information in yaml (I figured caching in memory will cause ever-larger memory growth), and changing the external node terminus to use the version of the facts as their version. This will usually result in the cached node information being used, instead of always hitting the external node app during file serving. Note that if the facts aren't changed by the client, then this will result in the cached node being used, but at this point, the client always updates its facts. (#1130)
f3a304c Modifying the yaml terminus base class to use the timestamp of the yaml file as the version of the object.
8b29368 Adding a filebucket test to puppet-test
da77cb6 Adding a test for local compiling
405802e Using the indirected facts rather than master.getfacts, so no factsync is used
388cf7c Regression in :node_name functionality
872ced7 Flat file now does writing to a tempfile.
4956323 Fixing #1132 -- host names can now have dashes anywhere. (Patch by freiheit.)
ecb873d Fixing #1118 -- downloading plugins and facts now ignores noop. Note that this changes the behaviour a bit -- the resource's noop setting always beats the global setting (previously, whichever was true would win).
e2370b3 Fixing the service-stop on debian, using the patch provided by DavidS
e8029cc Fixing the "tidy" type to use an option hash for specifying its parent class
c955f61 updating changelog for already-closed tickets
eecc22c Cache the same type we check for, hopefully fixes #1116
f1216f8 Revert "Cache the same type we check for, hopefully fixes #1116"
ca0b62a Cache the same type we check for, hopefully fixes #1116
35214eb Fixing the rest of #1113: External node commands can specify an environment and Puppet will now use it.
2261032 Partially fixing #1113: LDAP nodes now support environments, and the schema has been updated accordingly.
4c0f6c8 Fix for 1094
647f5b4 Always duplicating resource defaults in the parser, so that stacked metaparameter values do not result in all resources that receive a given default also getting those stacked values.
ee8fac6 Changed name of method for clarity per code review
8192475 Ticket #1041 The CA serial file was getting owned by root because it was using a different method to write to file
4c47656 Applies patches from #1111 and #1112
443db20 Fix tests depending on the Puppet[:localcert] file existing using stubs
8627139 Updating version number
3b5daf7 Revert "Fixes #1099 - use of -m option with -d option for home directories"
0ae58a9 Fixes #1099 - use of -m option with -d option for home directories
0.24.2
======
f019cac Updated to version 0.24.2
bfdac69 Updated to version 0.24.2
6faed12 updating changelog for 0.24.2
ee88c58 Applying patch by DavidS to fix #1083.
a7339ec Fixing a few tests
e008b02 Fixing #1110 -- transactions now always make sure their tags are arrays.
65b7267 Fixing the fact that resources that model defined resources were getting finished multiple times, which meant they got multiple copies of metaparams.
4c3fa78 Fixing a few more loading order issues.
857814a Fixing tests that did not work with Rails 2.
7ca0ad6 Fixing a test that changed the environment for all later tests, thus breaking some of them.
9b07758 * Tweaks for puppetshow UI cleanup
0139889 * Add migration for "created_at" (hobo expects it) * Tweaks for puppetshow interface cleanup * Delete unused tagging lib and puppet_class model
43aea83 renaming ral/types to ral/type in the tests
879ee22 Fixing #1062 by moving the yamldir setting to its own yaml section. This should keep the yamldir from being created on clients.
fd1573f Fixed #1047 -- Puppet's parser no longer changes the order in which statements are evaluated, which means that case statements can now set variables that are used by other variables.
9d6e926 Fixed #1063 -- the master correctly logs syntax errors when reparsing during a single run.
abd688e Fixing #1092 by no longer using the resource reference to look resources up, which means there's no concern about not finding the resource, which is where the nil was coming from. We now just iterate over the vertices.
29aafb4 Fixing an integration test so it cleans up after itself
82b02b9 Fixing #1101 -- puppetrun works again.
dd17d4c Fixing #1093 -- 0.23.2 clients are again compatible with 0.24.x servers. :ignore links is now equivalent to :manage links.
c0b5352 testing automatic commit emails
614ab9f Adding a 'control' parameter to services, for those service types that need a control variable to enable/disable.
bb8051b Removed the loglevels from the valid values for 'logoutput' in the Exec resource type -- the log levels are specified using the 'loglevel' parameter, not 'logoutput'. This never worked, or at least hasn't for ages, and now the docs are just correct.
ff4f65a replacing tabs with spaces in the redhat interface provider
f3db79e Fixing a typo in the mailalias resource type
4e55999 Removing the validation on package sources, since some platforms (e.g., hpux) do not have a well-formed requirement for the source.
42bfdf2 Fixing #1085, I think -- I was not returning a resource if the class had already been evaluated, but this was only being run into in corner cases -- mostly where one class included another class, I assume.
1258512 Fixing #1084 -- the node catalog asks the individual resources whether they're isomorphic, and they in turn ask the resource types (or default to true for defined resource types).
9a33487 adding a comment to the namespaceauth.conf file
04892ee Adding an example namespaceauth.conf
f0975df Trac #1038: not a fix, just an attempt at improving the situation.
c8b320e Corrected #1040 fix - this should now be right - trace was after raise
07cd482 Making a couple of other small fixes, requiring classes that were not being required in the right order.
ff97059 Somewhat refactored fileserving so that it no longer caches any objects, nor does it use Puppet's RAL resources. In the process, I fixed #894 (you can now copy links) and refactored other classes as necessary. Mostly it was fixing tests.
939c952 Fixes ticket #1080
f184228 Fixes ticket #1079 - added . support for tags
9b6e501 Fixing a test that was failing when a user-specific fileserver.conf actually exists.
5d35bc5 Fixes #1078 and includes new test
7976015 Removing a test I never migrated from test/unit.
279a0c5 Fixing a test that was actually reading in keys from the filesystem and failed when those keys were unreadable.
098a69c updating checksum for #1010 fix
b06767e Quashed commit of my fixes for #1010.
5e18b8d Hasstatus in the init service provider; it was just doing a boolean check, rather than comparing to :true.
60f18c2 Fixed minor documentation error
39a6756 Fixed #1073 - moved show_diff and other logic post config parse
f006e17 Fixed test for #1040
1f0ea5a Second attempt fix address ticket #1040
39f9818 Removing some extraneous debugging from a test.
d82bfd8 Attempt to fix #1040 - catching errors in compilation
e830f28 Fixed #1018 -- resources now have their namevars added as aliases in the resource catalog, just like they were added in the resource classes.
60dd569 Fixed #1037 -- remote unreadable files no longer have the permission denied exceptions caught, thus forbidding them from being replaced with 'nil'.
2de4654 converting parser ast node specs from setup/teardown to before/after
9927efb converting parser ast host class specs from setup/teardown to before/after
c86c1da converting node catalog specs from setup/teardown to before/after
61cdc2b converting indirector yaml specs from setup/teardown to before/after
f702096 converting facter indirector specs from setup/teardown to before/after
516e5b6 converting indirector checksum file specs from setup/teardown to before/after
d260b7e converting parser compilerspecs from setup/teardown to before/after
1913134 converting mount provider specs from setup/teardown to before/after
6781e10 converting indirector terminus specs from setup/teardown to before/after
dba64dd converting file serving configuration specs from setup/teardown to before/after
b4c8f99 converting indirector ldap node specs from setup/teardown to before/after
3cb1118 converting indirector direct file server specs from setup/teardown to before/after
9e632bc converting parsed mount provider specs from setup/teardown to before/after
becafab converting mount type specs from setup/teardown to before/after
034336b converting indirector file specs from setup/teardown to before/after
12f139c converting package type specs from setup/teardown to before/after
b8d5ce0 converting fileserving/configuration/parser specs from setup/teardown to before/after
eb0bdcb converting indirector/module_files specs from setup/teardown to before/after
22d6f9f converting ral/types/schedule specs away from setup/teardown
d04567a converting indirection specs away from setup/teardown to rspec compatible before/after usage
aa14ce7 moving setup() methods to before :each, so that the tests will run with rspec, as opposed to just rake (which calls them directly with ruby, as opposed to any spec binary)
f9f32c4 reordering spec binaries to prefer the local vendor/gems/rspec/bin/spec option
d11cd39 Fixing a failing test that resulted from a change in how checksums are created.
62d7616 Fixing the directory service provider's behaviour when there's no value for a given attribute.
f087df0 Fixed ticket #1072 - Debian directory updates
0eede76 Fixed Ticket 1009 - problem with plist xml parser. We do not need the plist parser for pkgdmg.
458cb23 Fixed ticket #1070 - puppetrun configuration parse problem
2e41803 Fixed ticket #1069 - removed remaining references to multiple configuration files
10d4d0e Fixed ticket #1065 - Solaris SMF manifests
8fa4120 Fixed ticket #1068 - Minor documentation fix
30128bd Really minor change to user creation in Leopard.
6013b25 Refactoring the incremental checksum generation slightly based on the code in type/file/checksum.rb.
aebd303 Enhancing the stand-alone checksums utility module with the rest of the checksums we're likely to use, and adding tests, which I somehow missed when I wrote this file.
df3fbc7 Fixed #1060 - Debian service removal and addition
5ef8a3e Changing portage to use Puppet::Error instead of Puppet::PackageError, fixing #1059.
c4f7c51 Fixing comment -- ticket #1027 instead of #1064
8920557 Fixing #1064 -- providers et al are now autoloaded from modules even when Autoload#loadall is used.
4829711 removing "lib" deprecation notice from autoloader
f8afe13 Fixed #1043 -- autoloading now searches the plugins directory in each module, in addition to the lib directory. The 'lib' directory is also deprecated, but supported for now to give people a chance to convert.
fe02591 Fixed #1003 -- Applying DavidS's patch to fix searching for tags in sql.
9b1bfc1 Fixed #992 -- Puppet is now compatible with gems 1.0.1.
0cfa1d2 Fixed #968 again, this time with tests -- parseonly works, including not compiling the configurations, and also storeconfigs is no longer required during parse-testing.
8367fdf Renaming the 'pfile' and 'pfilebucket' files to plain 'file' and 'filebucket'. This should have been done years ago.
a42c3ae Fixed #1021 -- the problem was that my method of determining the in-degree sometimes resulted in a lower number than the number of in-edges.
d406353 Removing the last vestiges of GRATR from the PGraph class
068b61e Removing obsolete references (they're in the indirection reference), and adding error handling to puppetdoc.
98dbfa2 Loading the mocha gem from the puppettest.rb file.
12fa0fa Fixing the Rakefile so all tests run in one task instead of multiple.
cb5def4 'rake' within the spec dir works now, anyway, which is a good start. Autotest still doesn't work, though.
eb74033 Fixing the puppet_rspec autotest plugin to use the modern interface
1b90f7f Trying to upgrade rspec, but not having much luck.
bcb9b56 Copying over Rick's work from the master branch supporting autotest and cleaning up the rspec support.
3af6827 Adding an inflection util class.
7e45553 Fixed #997 -- virtual defined types are no longer evaluated. NOTE: This introduces a behaviour change, in that you previously could realize a resource within a virtual defined resource, and now you must realize the entire defined resource, rather than just the contained resource.
c8da318 Moving the ast node tests to rspec (which I could have *sworn* I did this weekend). In the process, I fixed a couple of bugs related to differentiating between nodes and classes, and then cleaned up quite a few error messages.
8b2fae0 Removing the last remaining vestiges of GRATR -- removing the bangs from 'add_vertex!' and 'add_edge!'.
cf21ade Switching the Node catalog to use the Tagging module instead of its own tag methods.
744cd45 Added a 'tagged?' method to the Tagging module.
d21416b Switching the Node Catalog to using a separate method for validating that a given resource is unique within the catalog. This no longer allows any duplication, even with Execs.
fd0c5cb Changing the name of the Compile class to Compiler, since it's stupid to have a class named after a verb.
5ebaa89 Refactoring the interface between the Compile class and the AST::Node class to match that to the definitions and AST classes.
e247b56 Changing some methods in the Compile class to be more internally consistent (switched store_resource to add_resource, and store_override to add_override).
6a4cf6c Fixed #1030 - class and definition evaluation has been significantly refactored, fixing this problem and making the whole interplay between the classes, definitions, and nodes, and the Compile class much cleaner.
3b740ff Converting the Compile class to use a Node::Catalog instance as its resource container, instead of having its own behaviour around resource uniqueness.
194e730 Moving all of the tests for Puppet::Parser::Compile to rspec, so I can refactor the class to more heavily rely on a Node::Catalog instead of doing its own resource container management.
fb4bdc0 More AST refactoring -- each of the code wrapping classes just returns a resource from its evaluate() method, and all of the work is done in the evaluate_code method. This makes the code cleaner, because it means 1) evaluate() has the same prototype as all of the other AST classes, 2) evaluate() is no longer called indirectly through the Parser Resource class, and 3) the classes themselves are responsible for creating the resources, rather than it being done in the Compile class.
5a0e34b Refactoring the AST classes just a bit. I realized that all of the evaluate() methods only ever accepted a scope, and sometimes one other option, so I switched them all to use named arguments instead of a hash.
82720d5 Removing some obsolete code from the AST base class
dbaffae Ceasing autoloading ast files; loading them manually instead
7c500da Stubbing Facter during the snippet tests, so they are faster and work with no network
084d0fb Adding more information to dependencies that do not resolve
b293763 Applying patch by Jay to fix #989 -- missing crl files are correctly ignored, and you now use 'false' instead of 'none' to explicitly ignore them.
2931723 Fixing the Settings class so that it correctly handles file values that are false.
f7b0ca9 Fixed #1052 - fixed gentoo service management
b3f67ec Fix ticket 974. My original "fix" wasn't. This actually fixes the problem by using a regular expression that matches only up to the first square bracket.
8f0d87d Added :env parameter for backwards-compatibility, with warning about deprecation. :env parameter sets new :environment parameter. Changed instances of :env to :environment for consistency with other types. Added tests for new parameters. This cimmit fixes ticket 1007.
139ff33 Fujin's patch for ticket #1007 - consistent use of 'environment' instead of 'env'
aedd59c fix bug 974 - filenames with opening bracket characters generate exceptions
b8036a9 Updating the docs for the cron type
28a8577 Added hostname test for hosts type
16df87c Updated fix for ticket #151 and added a test
ed0c745 Fixing #1017 -- environment-specific modulepath is no longer ignored. (Cherry-picked from master.)
ade9f3c Store a resource before adding relations to it otherwise activerecord will complain. This fixes #933
047ec54 Fixed tickt #1034 - doco typo
6ff9423 Significantly refactoring the lexer, including adding Token and TokenList classes for managing how the tokens work.
11799b3 Fixed #1001
348aa3e Fixed #1028 - examples incorrect for 0.24.x
974fcdb Removed womble-specific Debian build section
321b8fd Fixed #1006 - changed ldapnodes to node_terminus
ee6ddc9 Removing tons of unnecessary calls to "nil?" from the lexer.
7a4935f Fixing a couple of tests, one related to recent tagging changes and one that somehow slipped through when I removed the GRATR code.
9a290bb Second attempt to fix ticket #151 - host type now validates IP addresses and hostnames/FQDNs
4a7fcfc Revert "Fixes ticket #151 - host type now validates IP addresses and hostnames/FQDNs - the regex for the latter is quite complex but I have found it bullet-proof in the past"
b561ae6 Fix bug #997, only evaluate non-virtual definitions
1ccc9c3 Fixes ticket #151 - host type now validates IP addresses and hostnames/FQDNs - the regex for the latter is quite complex but I have found it bullet-proof in the past
d7a89b4 Fixed #1019 - made libshadow available for non-Linux users
8a649ff I think I've finally fixed #959, by having the Settings class skip any resources that are already in memory.
52eba77 Fixing #794 -- consolidating the gentoo configuration files.
f43be56 Removing the line that marked fink as the default package manager on darwin.
f98be4a Fixing #976 -- both the full name of qualified classes and the class parts are now added as tags. I've also created a Tagging module that we should push throughout the rest of the system that uses tags.
2cbab2c Fixing #1008 -- Puppet no longer throws an exception when you've pointed a file at a source that doesn't exist and you specify 'ensure'.
f5674cd Fixing #995 -- puppetd no longer dies at startup if the server is not running.
7a9aae8 Wrapping the Resolv call in the mongrel server so if it fails it doesn't kill the server.
9161ae8 Applying a fix for #998 -- I used a patch equivalent to bartv's, although I could not use his commit because it was against the 'master' branch instead of 0.24.x.
046a326 Fixing #977 -- rundir is again set to 1777.
4618140 Updating docs for ssh.
7ee4746 Adding a parse test to puppet-test.
35145f3 Fixed ticket #1005 - added additional logcheck lines
b24ac77 Fixes ticket #1004 - documentation fixes for ralsh and puppetrun
1ff9d65 Updated documentation for builtin cron type; added information about range and step syntaxes.
f15696c Updated tagmail documentation fixing ticket #996
e3d4ea8 Fixes ticket #993 - tagmail with smtpserver specified does not add To/From/Subject header
40addcd Fixing #982 -- I have completely removed the GRATR graph library from the system, and implemented my own topsort method.
927dff4 Fixing #971 -- classes can once again be included multiple times.
117926c Fixing the unit tests for nagios_maker; I could swear I'd already done this but I must not have committed it.
a7bca7e Removing the requirement in the parsed mount provider that the fstab file exist.
1bdf3f8 Fixed #984 - Added Debian to reponsefile doco
b1f13af Fixed #980 - minor wiki formatting error in nagios_maker.rb
2f9c13b Fixed ticket #979 - code configuration option doco
039dc8d Fixed ticket #979 - pkgdmg.rb documentation
1154c42 Fixed ticket #978 - logcheck/puppet
33e319a Added builtin support for all Nagios resource types. I use Naginator to parse and generate the files, with ParsedFile to handle record management and the like.
68cde4f Removing the one-off naginator provider for nagios_command.
348f257 Adding the metaprogramming to create the Nagios types and Naginator providers. This is basically all of the code that's necessary to create all of the needed Nagios types.
4e8bc40 Fixing the inability to manage '/' directly. It was a result of stripping extra and trailing slashes.
9b1d036 Adding the first round of Nagios code. There are no tests here, but at least a single Nagios type is functional. Now I need to do some metaprogramming so this works for all nagios types, and add tests for the whole thing.
20367c6 Updated for 0.24.1
20d430d Adding 0.24.1 tag to the changelog.
0.24.1
======
4fa6546 Updated to version 0.24.1
d17fb7a Updated to version 0.24.1
40439da Updating an exception message a bit.
e2fc425 Attempting to fix #952 -- catching any exceptions thrown during a run.
c59ff62 Further fixes toward #965. Turned out that the previous fix caused other problems.
4d28b10 Updating the failure when the CRL is missing, so it's clear how to solve the problem.
e4446b6 Fixing parseonly with a modified version of jay's patch from #968.
bc0616e Updating filetype detection for vim, and changing the filestructure for vim files. (#900 and #963)
927cb24 Fixing #967 -- default resources no longer conflict with managed resources.
c998a25 Adding a --print option to puppetca that just prints the full-text version of a certificate, and --verify, which uses the external openssl command to verify the cert against the CA cert (I could not find an option to the builtin Ruby libraries to do this).
9c32c9c Removing the ability to disable http-keep alive, since it didn't work and is now unnecessary.
553b2ad Entirely refactoring http keep-alive. There's now a central module responsible for managing the http pool (Puppet::Network::HttpPool), and it also handles setting certificate information. This gets rid of what were otherwise long chains of method calls, and it makes the code paths much clearer.
92b0ebc Fixing #967 -- relationships now work when running 0.23.x clients against 0.24.0 servers.
1ada24d Fixing some tests that were failing with the recent ruby that has ssl issues.
c22a584 Uninstalling packages through 'ensure => absent' works again for the rpm and yum providers.
8f5989a Updated for 0.24.0-2
cc2d532 Updated for 0.24.0
933b1df Fixing #961 -- closing existing, open connections when a new connection is requested, and closing all connections at the end of each run.
e0dab9a Updating changelog to reflect the fact that we no longer warn about explicit plugin mounts.
4d3a368 Remove the warning about an explicit plugins mount.
178093f Fixing the Rakefile to include the yumhelper.py file in the file list.
0.24.0
======
6b02bd5 Updated to version 0.24.0
e92f1cc Updated to version 0.24.0
22daebe Adding changelog update for misspiggy/0.24.0
e0f5444 Fixing the webrick test to provide a correct host name so the stupid ssl checks pass during the test.
106f319 Changing the statefile to only being managed by clients, not by puppetmasterd.
4ebb8d0 Hopefully finally fixing #959. Loading the stored cache resulted in the resource duplication, based on how the settings are used, so I added a test to only use those settings if the directories do not exist.
690e287 This should be the last fix for exported resources. Hosts were keeping the export bit on all resources, even when they'd collected another host's resources, which caused a duplicate copy that was still exported.
f1169ee Not using the main section when running the store report, since it is unneeded and can cause conflicts within puppetmasterd
ce5cab1 Removing extraneous debugging from the schedule resource type.
cb0c4ee Renaming 'configuration' to 'catalog', fixing #954.
7ac3bd7 Renaming the 'null' terminus type to 'plain', as requested in #960.
a21ee00 Copying the fact-loading code from the network client to the Facter terminus until I have a better solution. This problem was discovered becomes of #958.
1bbaf18 Applying patch by whaymond to fix #955.
d9200a0 Adding what is hopefully the last commit for #896. Here's the changelog:
74db777 Removing the 'addpath' commands from the freebsd service provider, since it's no longer needed or even valid.
b19a0c9 Removing the recently-commited paludis provider, because it breaks autoloading as indicated in #956.
02b64ab Applying patch by josb in #884 to provide pattern matching in the tidy type.
584127c Applying patch by raj in #881.
4ee5ab8 Applying patch for portage package support from thansen in #895.
ed642ac Replacing freebsd service provider with the one provided by raj in #880.
117f005 Adding paludis package support as provided by KillerFox in #741.
3248c93 Fixing #937 -- I had not ported the dot methods at all, and I had to make a few small changes to make them work.
a8bf74b Fixing #946.
b70f00a Fixing some further failing tests resulting from the fix for
862d1f7 Adding an Indirection reference, along with the work necessary to support it.
da77e4a Updating the changelog with external node info.
f127d04 Fixing #951 -- external nodes work again, but you have to set the 'node_terminus' setting to 'exec'.
7a4ae08 Fixing the rest of #948. My previous work was sufficient, except that I was not passing the interpolated value in to the hook, which meant the libdir was set to something like $vardir/lib.
3790ce1 Fixing part of #948 -- per-setting hooks are now called when the configuration file is parsed. The bug is still there, but I'm getting closer.
b852c2f Fixing #941 -- calling pkg_info instead of info in the openbsd package provider.
ae33e57 Fixing #923 (again). The host storage method was not correctly searching for the host, so it was creating a new host on each run, which is what was causing the conflict.
9ad7d1a Adding basic unit tests for type/user by DavidS from #948.
038b9c8 Fixing #923. Resources that are collected on the local host are no longer marked as not exported.
5886d37 Applying patch by whaymond_home to further fix part of #896.
072b03e simplify PluginsMount
a012849 Updated tests for http_enable_post_connection_check configuration setting.
4d4abd3 Better test to match the behavior of the code.
24cacdb Fixed test case for http_enable_post_connection_check
f94d6d3 As per lutter; augmented fix for #896 to be configurable and defaulting to validate the server certificate, honoring CVE-2007-5162.
8eecbe5 Fixing another failing test I somehow missed in my last big commit
88304cc Renaming @model to @resource in a provider
75647ee Fixing a couple of tests that were failing on a different platform or with a different version of ruby
811fefa Fixing #892 -- filesystem mounts are no longer remounted.
dedc56a Fixing #527 (rewrote service tests), #766 (services only restart when they are running), and #918 (service tests fail when hddtemp is not installed).
421b3fc Another backward compatibility patch, this time helping with a new server and old client
bbf8a8b Making a few changes to the transportable class to enhance backward compatibility
11ae473 Theoretically, this patch is to fix #917 (which it does), but there were enough problems fixing it that I decided something more drastic needed to be done.
8127397 Fixing puppetca so it passes its tests, duh. Apparently wyvern's patch broke things a bit and I was stupid enough not to run the tess right before accepting.
2282046 Adding a top-level ResourceReference class that everything else can use to canonize how we refer to resources. Finally.
c6d1746 Fixing the first half of #917 -- the ResourcReference AST code now correctly finds the resource. It's getting lost in the configuration translation, though, so I need to fix that, too.
6c1d8d3 Applying fix to xmlrpc client tests by Matt Palmer
6b2c0d8 Fixing the error message as requested in #893.
1b2142b Applying patches from #823 by wyvern
c7cd7ec Fixing the markup on the pkgdmg provider so it is a bit better
1e6ba6f Fixing #781, from what I can tell. I'm leaving it with no tests for now, since it's a very small chunk of code and it's *insanely* difficult to test this kind problem.
5d30ea9 Fixing #810 -- I catch the error and prefix it with something a bit more useful.
4e52ffc Fixing #796 -- the fileserver can now start with no configuration file (it creates both default mount points if it does) and puppetmasterd no longer requires the configuration file to exist.
168fa5f Fixing the asuser method in Puppet::Util::SUIDManager so that it correctly just yields if you're not root. It also no longer tries to set :uid or :gid; just :euid and :egid, and it once again sets :egid before it sets :euid, which is important because you usually can't change your group after you've changed your user id.
0ef6b95 Fixing #931 by keeping track in configurations of what transportable resources get converted to, so different names don't throw it off.
a38b415 Fixing #927 -- rewriting the test to actually test what it's supposed to be doing and to skip the whole network connect thing.
7ff8ea5 Fixing the persistent and periodic schedule test failures by rewriting the schedule tests entirely.
18b4c3a Fixing #924 -- clearing the configuration cache before and after the test.
2cb1199 Fixing the breakage that I caused when I added the 'declared_feature?' method to provider features.
2d19ee2 Fixing #920 -- I have replaced the existing mount test with an rspec version. It's not perfect, in that it only tests the :ensure state, but that's where 90% of the behaviour is.
c3dde68 Fixing #919 -- installed packages used for testing are just ignored, rather than throwing a failure.
47890f9 Fixing a test that was erroneously testing for the wrong feature
12ebbe2 Rewriting the tests for the package resource type, fixing #930.
fc7f1b4 Fixing #921, mostly by just deleting the existing test. I had already migrated all of the tests into rspec but forgot about these tests -- they were only in the rails/ subdir because people kept not running the parser/ tests after modifying the Rails code.
9311bdd Applying patch by trombik from #756.
b575d15 Integrating Matt Palmer's patch to provide a 'plugins' mount, fixing #891. The patch was ported to the current code by David Schmitt, I applied the rest of Matt's patches, and I then fixed all of the code so that the tests passed.
36c947e Fix #896 - Always disable DNS checking of certificate when making https connections.
3fb8e2e Applying the rest of Matt Palmer's patches related to providing a plugin mount.
7eb09ab Implementing the test for setting the Rails log level.
676efa7 Incorporating patch 20071030034736-6856b-6004090b3968cdbf7d366a03ee1c44e2160a3fe0.patch from womble, and rewriting and significantly enhancing the unit tests for the Puppet::Parser::Collector class; it should have full coverage now. There are no integration tests for it, so there's still no guarantee that it works at all, but hey, we're a lot better off than we were.
7f1b2d6 change up rails specs again with Luke's help
8de1412 Integrating most of Matt Palmer's from http://theshed.hezmatt.org/mattshacks/puppet/_patches/puppet-0.23.2/.
a88891a Fixed #906 - Augmented Cert DN regexp check to work with Pound and Apache.
c19d08a mock all use of Puppet[] in Puppet::Rails.database_arguments
e69e0c3 fix spacing
b435f04 fix socket argument to AR and add rails spec
e53693e Hopefully fixing #698 -- fixing the markup for the pkgdmg package provider
7c36ae9 Adding patch 20071030035457-6856b-bd1c45ed5ecd753b2cb4f05347061f7245cc175a.patch from womble -- Force removal of directories during pluginsync
880a8e2 Adding patch 20071020020745-6856b-dbc63ff3f137a4039fb997b9978202d52f621e8c.patch from womble -- Fix some residual instances of /var/run fever
696f1fb Adding patch 20071020015958-6856b-69efa7868cf3df3f2a2da6fcfc3b794bbb532c7f.patch from womble -- Remove rundir from puppet.conf, and add a NEWS entry to document these changes
7a95017 Adding part of patch 20071020011907-6856b-05b59120fdb90ab4a5842f91613247b07206a4ba.patch from womble -- Fix for Debian#447314, by fiddling with /var/run/puppet. This does not accept the whole patch, because the change needs to be tested around other platforms.
38b970a Adding patch 20070927050018-6856b-7fa134180aceb9cee2e667630345f5f8467a9d0c.patch from womble -- Catch more retryable errors in the XMLRPC call wrapper
276034f Adding patch 20070927042000-6856b-38a0c82fd0a0d950937e7fe5a38b9901743402b3.patch from womble -- Recycle the connection more aggressively, to stop problems with clients that are newly requesting certificates
3bf7031 Adding patch 20070926235454-6856b-079fc12a9b63d59afd59aa205bc8bfeb350b097a.patch from womble -- Recycle the connection if we're presented with an EPIPE
0ebd99e Adding patch 20070926214630-6856b-edd313b08555033710c90a94d9d8beaf889d6cf4.patch from womble -- Fix spelling mistake in debian control files
7ed1c17 Adding patch 20070913032650-6856b-b1cca1c249415c6076ffcecb9df1525a728457c7.patch from womble -- Fix annoying database deletion error for ParamValue objects.
28430c4 Adding patch 20070913032546-6856b-0de200e8450920e7f712c54bf287ae43c7fda8af.patch from womble -- Only set dbuser if explicitly asked for
d7b381b Adding patch 20070913011122-6856b-98bf03f09c8e19679390d73fdddc2e4d1273f698.patch from womble -- Add changelog entries for the pulled pgsql patches
a7d75d3 Adding patch 20070913010926-6856b-eb64be3b5169b7af674388124b406a1db7470880.patch from womble -- More restrictive permissions on some puppet-related directories
407734f Adding patch 20070913005414-6856b-db5ea77e10ec6869ad01a4bd6483912c337f3a70.patch from womble -- NEWS for the ssldir transition
1486d39 Applying patch 20070913004017-6856b-cdbbba99de0b33b64874205a27833b5114fcc6b9.patch by womble -- Allow empty config settings
03c8ffd Adding patch 20070913003810-6856b-cdc8b2e8c6c46eb8d6d073f86291a0fc5a59f429.patch from womble -- Only set the hostname and password if we want them; this allows pgsql ident auth to work it's magic
035fa38 Adding patch 20070905004837-6856b-2e7b8d8595ee0883537620c46424a4bf6174dc6a.patch from womble -- Add an attr_accessor for @http#ca_file, since older versions of libopenssl-ruby only provides ca_file=, not ca_file
63b205a Adding patch 20070831053637-6856b-dd0fddab681485ce7cea0b57336d0c48fa33f7f8.patch from womble; updates changelog
72c0e7b Adding the debian directory via patch 20070831052721-6856b-b90bb56a4ed37ea420f10352a0a366068cddc7e4.patch from womble
7efe24f Fixing #882 -- I just added a quick hook to the Master handler again; we need a better long-term solution, though.
56aad69 Patching a bit for #804 by making the maximum much higher UID and making it tunable, but it has not gone away yet.
a525ab5 Fixing a couple of tests that were failing because of the environment changes.
6d74ddd Accepting a modified form of the patch from #885 by immerda.
b745f04 Fixing #886 -- the problem was the I had changed the base class for Parameter, which apparently lost the 'nodoc' method for that class.
dbe70a1 Added calls to endgrent/endpwent in util/posix.rb to fix #791.
7f504b0 Applying patch from #896 by whaymond_home, adding more certname aliases.
1cb40ec Obviating targets in interfaces; they now just generate a warning.
eee9f5e Adding more tests to the redhat interface provider. It no longer uses the :target parameter (which I'll be removing in the next commit).
1a4e4fb Rewriting the sunos interface provider to manually parse and generate, rather than using ParsedFile. This should fix #777, and has from what I can tell.
8cbe8bd Adding unit tests for the sunos interface provider.
3d2e1a5 Adding some unit tests for the interface type before i go messing around with it
cca613d Fixing the first part of #787. Not all collections were being evaluated on the first pass because they were being deleted from the collections list during evaluation, which caused some to get skipped. This commit fixes that problem, which helps in the trivial cases where the collections are in the same scope. I expect it's still broken for more complicated usages.
96b3cde Applying patch from #834, apparently fixing a problem with bringing up alias interfaces.
9472eef Removing the bootproto and broadcast attributes from the redhat interface provider, since they are not needed
a7a46af fixing the path to the spec helper in the exec test
3d31dc8 Fixing #762. The main problem was that I accepted the patch in #744 which broke the templates. In the process, I also added test code for the redhat interface provider and rewrote how parsing worked to make it more testable.
8ecdfc2 Moving the exec test into the types/ directory
94e63ad Fixing the last failing test relating to the environment changes
7fe5bfc Fixing the exec spec so it works when non-root and is a bit cleaner
8cc07ad Using the Environment class to determine the default environment, rather than plenty of different places having the logic of how to determine the default environment.
53008e5 The Puppet settings instance now validates environments when you set an environment.
9e5fc76 Fixing #911 and #912 -- there's a default environment (development) and you have to specify the valid environments for your site.
cc88441 Removing the manual ssldir setting by David in 59626cb3907d36e4fd762277daa76f523faf0908
1bf3999 Fixing a failing test from my fix for #446 -- I had changed the behaviour of Resource#override_parameter unintentionally. I've corrected the comments so it's clear why the original behaviour was there.
3f0b250 Fixing a few test suites that passed when run as part of the suite, but failed when run individually. The problem was that I changed lib/puppettest/support/utils to have a separate module and I didn't test the individual files.
4bd7b6f Fixing #896 by applying DerekW's patches, with slight modifications to fit coding style.
8ad2732 Fixing #446. I ended up largely not using porridge's patch, but only because the code (and my coding style, to some extent) has changed so much in the last few months. Also, added specs.
1b78f57 Add Exec{ logoutput=> on_failure }
2b14f62 Reverting the changes I'd made toward removing the global resources. These are commits:
9cf477b Applying fix by Jeff McCune from #905
edc4b1d Fixing a SimpleGraph unit test so it doesn't depend on hashing.
c19835c Fixed most failing tests, but there are still over thirty failing.
4afbaa6 fix #903: add patch from hrvojehr
32d9afc tests for #903: fail when no logoutput is generated on failure
9290cc8 Modifying how default resources are created; they are now added to the configuration by the master client, rather than by the creating types.
ffb4c2d This commit is the first run at removing all global references to resources. It deprecates the class-level [] and []= methods, used for so long to provide closure behaviour but now unnecessary with the node configuration's ability to function as a resource container.
b65fb83 Fixing a parser test -- really, just removing tests that belong with the AST classes rather than in the parser.
72510bf Fixing #800 by refactoring how configurations are retrieved from the server. The real problem was getting all of the validation done before any caching, which required a good bit more refactoring than I expected.
dd7caa7 Moving some compile tests to the spec/ directory, and switching the node scope to no longer be lazy evaluation, just like I switched 'main'. When I made all of these classes and nodes lazy evaluated, I should have decoupled my real goal (using resources to evaluate them) from the idea of lazy-evaluating them, and this basically does that.
47a2605 Changing the 'main' class to no longer be lazy-evaluated. It was getting evaluated after node classes, which caused even stranger ordering issues.
a4e8f1c Adding a memory terminus for facts, which is really only used for testing
3851415 fix dependency on $HOME, which causes massive failures when running without environment
59626cb fix failing CA test, when testing with incomplete setup (no ssldir, no DNS)
a6ad326 fix the underlying dependency on the environment in the cron type
d48ee3e fix crontests depending on ENV[USER] by using Etc.getpwuid(Process.uid) instead
8fe892d fix a testfailure when running spec tests as root
445c29c fix #872: improve property(:content).insync?
5726412 tests for #872: check interaction between "replace" and "content"
61ef289 fix #815: add :main to all use() for :reporting and :metrics
418bc21 remove obsolete runners variable
a535cbb Commenting out the time debugging I was using
3f583dc Adding unit tests for the module that handles the logic around mounting and unmounting. This includes a fix for bug #761, which required a different regex for Solaris.
8f04446 Fixing the 'mount' tests so that they no longer modify the local system and they run fine as non-root users.
ba19989 Switching the class resource evaluation to only happen when using :include, not (for example) when evaluating node classes.
cf75168 Classes once again get evaluated immediately when the 'include' function is used, instead of being lazy-evaluated.
4441052 fix #891: create a plugins mount which collects all modules' plugins/ subdirs
dfe774f Switching the base class for the Relationship class. It was previously using the GRATR::Edge class, which had wonky overrides that dramatically slowed down sorting (its hash mechanism hashed the source and target so that edges with the same source/target got the same hash, which we actually don't want any more).
4194526 fix #760: property_fix has to be called after creating a symlink
b250416 fix #731: add exported=true to collect_exported
1ffcce0 Splitting the puppetd tests into two tests. It is still not a very good test, but I do not know of a good way to test this, really.
065a1d0 Switching the graph base class from GRATR::Digraph to Puppet::SimpleGraph, which should dramatically enhance performance. It should be largely functionally equivalent, with the only difference being that edges are no longer deduplicated.
3f21e93 Adding a new graphing base class, because the GRATR stuff is just too slow. This class has just about no iteration, and vertex deletation is dramatically (as in, 1000x) faster). Here are the results of some very simplistic graph operations:
ef99495 Caching the 'parent' value, which resulted in a drastic performance increase.
826efe8 The configurations should now be functional again -- file recursion was previously not working, because the relationship graph was setting itself as a resource's primary configuration, which caused it to try creating its own relationship graph.
db293cf Fixing a bit of indentation and commenting in the xmlrpc/client file
956daa5 This won't be perfect by any stretch, but put in a moderately reasonable autotest config file.
c7b36b7 One significant step closer to getting autotest running properly on the Puppet specs. Created a spec/lib/monkey_patches/ directory for holding patches to RSpec functionality. Extraced 'confine' and 'runnable?' support from the local copy of RSpec (spec/lib/spec/) and now load them from the monkey_patches/ directory. Fixed a bad include in one of the specs. Made it possible for the gem-installed spec binary (which autotest calls) to be used with Puppet. Imported the Autotest::Rspec class, created a PuppetRspec autotest class, added a discovery.rb file for autotest to pick these up.
6585835 Adding patch from #879 by tim
d03f68e Changing the test/ classes so that they work from the main test/ dir or from their own working dir, like the specs do. This was just a question of changing how their libraries are loaded.
c0a07ac File serving should work now, both recursive and single files, across modules, local file system, and the traditional file server.
54fc80d Exceptions on requests are now captured, exceptions are serialized, and exception text is passed back via REST.
e7bfe0b Finish serializing successful results (via calls to to_yaml, etc.) for REST handlers. Refactor request building in REST handler specs.
d28a904 REST handlers now properly returning 200 status on success.
1746751 Adding post- hooks for :find and :search in the indirection class.
09f9c3c Adding the calls to the authorization hooks in the Indirection.
b874751 Renaming the FileServing TerminusSelector module to IndirectionHooks, because I'm going to add some hooks for transforming returned objects.
de5d91e Renaming the :local termini for metadata and content to :file.
7fa99b0 Link handling is now in the file serving classes. This was done by putting all of the functionality in the Content and Metadata class (actually, in a new base class for them).
688fcdf Adding searchability to the fileserving termini, using the new Fileset class.
393a3e8 Adding a Fileset class for managing sets of files. This is the new server-side for file recursion, and I'll next be hooking it to the fileserving 'search' methods. This is basically a mechanism for abstracting that search functionality into a single class.
b2b8f75 Adding authorization hooks to the file_server and module_files indirection terminus types. Both hooks use the fileserver configuration, but the module_files hook only uses the 'modules' mount.
8f827ff Renaming the 'mounts' terminus to 'file_server', and renaming tests accordingly.
08099b7 File serving now works. I've tested a couple of ways to use it, and added integration tests at the most important hook points.
264331b Partial work done for ssl certificates.
ec39672 Adding this test stub that's been sitting around in my repository for a while.
fc60751 I've now split the file-serving termini into two separate types (in addition to Rest): A local terminus that just uses direct file paths, and a mounts terminus that uses the file server to figure out what the path should be.
64c6700 Fixing all of the classes that I just renamed, and adding the TerminusSelector module to the File Metadata indirection.
56b83fe Renaming the file serving indirection termini to match the standards I set in the TerminusSelector.
33d7dc0 I'm working on making file serving work in the indirector now, so I added two abilities to the indirections: Models can specify a module to extend the indirection instance with, and indirections will use a :select_terminus method, if it's available, to select the terminus to use for finding. (It's currently only used for finding, not destroying or saving.)
8156185 Renaming the file_serving/{content,metadata} indirections so that they make more sense in the REST API, and creating stub tests for the indirection termini. Now it's on to create the rest of the tests for them.
2718b63 This is the first mostly functional commit of the new file serving structure. The next step is to hook it up to the indirection so we can start writing integration tests to see if we can actually serve up files.
e1dd5dd Adding spec stubs for authorization in the indirection
e69a50a Fix test which is conditional on mongrel installation.
8bf5196 Oops, forgot this file in my last commit.
d0bd48c Adding the first pass at modifying file serving to work with indirection. I've split the fileserver handler into four pieces: Mount (which so far I've just copied wholesale), Configuration (responsible for reading the configuration file and determining what's allowed), Metadata (retrieves information about the files), and Content (retrieves the actual file content).
d2b891f More specs, fleshing out the returns from REST
e5921c5 getting more fine-grained with the response specs -- the target is always moving.
705f76f Argument passing now supported on {webrick,mongrel}+REST.
ce34968 Make the actual runtime be more robust when mongrel is not installed.
6cd0f37 Make it possible to run all tests even if mongrel isn't installed. Shouldn't "confine" produce some output when running spec? Who knows.
216dd8c Refactoring, argument processing for model methods.
abbc824 Tweak to move model lookup functionality into the Handler base class where it belongs. Robustifying the request sanitization a bit more.
2a497ff Refactored to use a Handler base class for server+protocol handlers. Finally eliminated dependency on Puppet.start, etc., from WEBrick HTTP server class. {webrick,mongrel}+REST now support request handling uniformly; need encode/decode next.
6ab78f6 Inlined the controller, eliminating a class. Mongrel+REST has the right bits for request handling prior to the encode/decode/exception-handling bits. Refactored to make the common logic extractable to a base class.
b8c877c Registration now built for {webrick,mongrel} REST handlers.
3c370b3 Going back to each server+protocol object being responsible for only one indirection, as the REST vs. XMLRPC models are different enough that the object must register itself on initialization and handle the request when it comes in.
c06edda First pass through initializers of {mongrel, webrick} REST handlers; hooks into Indirection to look up models from indirected names.
ab4c7fa Minor tweaks to make the ::Server initialization a bit more robust. Fail on unknown HTTP Server types; fail fast.
099c546 Finish front end of delegation to server+protocol helper classes ("handlers").
b1d6223 Bringing in initial handlers for server+protocol pairs.
a815f78 Reorganizing the file structure for indirection terminus types.
ba95202 Partial support for building Handlers for all handler-protocol pairs.
ef8ebe0 Implementing address & port support for new webrick server.
c34efbc Hooking up address/port support for the various servers w/ specs. Still need to start up a webrick server w/ address + port (this is far too incestuous with Puppet lib & Puppet.start at the moment).
9a179ec trivial: WEBRick -> WEBrick, to be more consistent with how the WEBrick ruby classes are named.
e56406f Implementing listening state tracking for webrick and mongrel.
ec71e05 More unit specs for mongrel and webrick; more code to make them work, yo.
31384fe Pushing functionality down to webrick/mongrel classes now; cleanup in the base server / http server classes + specs.
694f98b Fixing failing tests, including making the debian service provider test work on non-Debian platforms.
29feac0 Translating the report handler to an indirected model. I've provided backward compatibility with the old handler.
74d77f7 Adding version handling through most of the indirection work. This counts as the first commit where configuration compiling actually uses the caching correctly according to the application model.
e90191a more stuff for the interim commit
10039b9 interim checkin of network stuffs
512096a Fixing some small spec failures resulting from test fixes. The problem was in how TransObjects were converted to RAL resources. (Committed while flying over Arkansas.)
d24c1cc All tests should now pass again.
ec58355 Fixed #819. Applied patch provided by matsuu.
7ac7872 Fixed #822. Applied patch provided by DavidS.
fc9c850 Adding support for versions and freshness-checking to the indirection layers. This should hopefully enable the different application models we need in our different executables.
1befcc4 Homing in on a clean separation of concerns for a low-coupling, high-cohesion "server" model that will handle REST and/or XMLRPC on webrick and/or mongrel.
5c32c8e Somewhat better documentation of the :absent field feature in fileparsing.
d055cbc Make it apparent that absent fields in a record have a value of :absent, which is different from what appears in a line.
b6dc1ae Trivial tweak on HTTPServer module file
a7d220b Moving the webrick/mongrel "servers" over to HTTPServer module instead of Server. Using Server as the master class for client connections. Server (former RESTServer) will instantiate the appropriate subclass based upon Puppet configurator setting. There are now tests broken in the network section which I can't seem to figure out yet. Not a happy place to be.
cdaad28 Fixing error thrown when the end of the file is encountered unexpectedly
7d7e428 Removing obsolete comment
f084d83 Another round of test-fixing around the changes I made to the configuration system. 'puppet' itself still works, even with -e, but I expect that puppetd and puppetmasterd are broken, and there are still quite a few broken tests because the default fact store can't write but that's the default behaviour for a networked configuration master.
9c58c47 Adding a :code setting for specifying code to run instead of a manifest, and removing all of the ambiguity around whether an interpreter gets its own file specified or uses the central setting.
d35cd94 Making "null" the default node source, so nodes are at least created easily
0e336bf This commit is focused on getting the 'puppet' executable to work. As a result, it involves a lot of integration-level testing, and a lot of small design changes to make the code actually work.
1fa5912 Adding the integration tests to the Rakefile for spec, fixing the integration tests, and extending the Classmethods for the indirector so that indirected classes can set the terminus class and cache class.
a93db87 Adding another test to the ldap node source -- we make sure we throw an appropriate exception if a parent is specified but we cannot find it.
9984a35 Fixing some terminology so some ldap tests are easier to read.
6acde71 Switching the indirection from using settings for configuration to requiring explicit configuration. This means that if you as an application developer want to use a different indirection terminus then you have to specify it; something like:
8ba3a70 Fixed #838. Applied patch provided by DavidS to add more robust update functionality to the dpkg provider.
f41c843 Fixed #837. Added freebsd service provider by trombik.
533ce4b Fixed #855, but I didn't add any tests.
19ad238 Fixed #827. Applied a form of the patch provided by porridge and wrote a test.
29accba Minor tweaks.
2412199 Allow for multiple REST servers to be active; some terminology changes in spec; fleshing out more behavior, implementing.
102ad23 Added .listening to REST server, handle listen states and transitions.
187d910 Spec'd a reset() method for clearing out known routes. Uses the unregister method so that any hooks there will be run. Probably a violation of YAGNI, but I'm willing to suffer it :-)
fd841b3 Updating first portion of the Network RESTServer spec with example code, getting the added examples to pass.
9236179 Attempting to reproduce and fix #829 by applying patch by Paul. I could not get a test to show the exception, nor could I figure out how the coding bug could have actually had an impact, but it's an innocent-enough fix, so I'm fine applying it.
e5c623e Fixing tests for the Configuration object, since I added the any_failed? test to Transactions.
938f051 Fixing #817, mostly using the patch by DavidS. I could not directly use the patch because I have refactored too much.
fd11603 Removing the Id tags from all of the files
bb3b3ce I finally tracked down the problem that was causing providers to sometimes suddenly disappear and thus tests to fail -- Kernel.require was not loading the normal ruby path (e.g., 'puppet/type/cron'), so if someone else loaded that then it would replace the in-memory type with a new one, but that new one couldn't load its own providers, because the Kernel would ignore the providers, thinking they were already loaded.
782bc4d Fixing the yaml path so that it is correctly created for puppetmasterd.
7c8fc8b Fixed #854.
d4afe39 Fixing #813 -- empty configurations again work.
5d50ca7 Fixing #814 -- when files are missing, the exceptions should now be more reasonable.
1be1db9 Updated CHANGELOG.
0b8893b Fixed #832. Added the '--no-daemonize' option to puppetd and puppetmasterd. The default behavior of 'verbose' and 'debug' no longer cause puppetd and puppetmasterd to not daemonize.
b45a7ca Adding more behaviours to the Puppet::Module spec, and fixing some bugs in the process.
3f90ddb Interpreting "hidden" class from spec drafts as a REST Controller. This name, functionality, and/or location in the tree is subject to change, but it's down now somewhere so we can move forward on it.
861c21d Added partial spec for the serving of REST information, as well as some client-side REST terminus behavior.
8722e43 Use external helper script to talk to yum; should avoid any more trouble with "yum list". Fixes trac #836
1174d99 Fixed a failing test where we presumed that non-string Fact values would have type preserved across a P::N::Client.master.facts call, which is not true.
7fe18e3 Fixed a test which was secretly sneaking off and pulling certs from ~ if they were there: Added set_mygroup method, removed duplicate setme method. Included PuppetTest in the XMLRPC servlect test.
fa643e6 Adding more indirection termini, mostly focused on caching information in yaml.
938b918 Adding cache support to indirection. If you have a '<indirection>_cache' setting, then the indirection will use the value there as the name of the cache.
06ad6a3 Updated the configuration doc to more clearly explain where puppet.conf is expected to be by default.
c8d02bd Fixing ralsh to use a configuration instead of a component
ffaa8ce Demoting the "file does not exist" log to debug from notice
c3c3e51 Fixing a small problem with the mailman type
f8ab62b Renamed princs to principals in the k5login type.
6079348 Added k5login type written by Digant Kasundra. This is for ticket #759.
2e33061 I changed the Terminus class to switch camelcase to underscore-separated words, e.g., FactStore becomes fact_store.
d6fd60c Removing obsolete fact stores and node sources. The functionality has been moved into the indirector.
cdc8ea6 Taking a first stab at moving configuration compiling into the indirection system. There are still quite a few unanswered questions, the two most notable being embodied in unimplemented tests in the Configuration Code terminus.
c40da33 Adding a "memory" node terminus, which will be used by 'puppet' and the Cfengine 'module_puppet', since they need to set up the node specially with classes and other weird things.
1e7c648 Fixing the spec for the checksum terminus to match the changed design in the previous commit.
048464f Adding my first integration test, verifying that checksum interaction behaves as I expect when interacting with the file terminus.
84146d0 Adding the first version of checksum support, which will acquire the behaviour of FileBuckets.
3a18348 Renaming the 'Puppet::Util::Config' class to 'Puppet::Util::Settings'. This is to clear up confusion caused by the fact that we now have a 'Configuration' class to model host configurations, or any set of resources as a "configuration".
e552c83 Adding the base file terminus. This will, at the least, be used as the back end for filebuckets and the certificate authority.
86dde63 All tests now pass in this configuration branch, which means it's time to merge it back into the indirection branch.
60cd6a7 The structure for handling resource generation is now in place, which means I'm over the hump in developing this branch.
a666995 Adding the last tests for the ldap node terminus. I managed to forget the tests around the main find() method.
ebe7290 All indirections are working, and they have all been migrated over to the new organization. Where we would have previously had an 'ldap' node terminus at puppet/indirector/node/ldap.rb, we would not have it at puppet/indirector/ldap/node.rb, and it would be a subclass of puppet/indirector/ldap.rb.
b9dc6cb It looks like the new indirection setup is complete.
02275f0 Adding automatic association between terminus subclasses and the indirection they're working with. It looks like I'll be moving terminus registration to the indirection rather than the top-level Indirector.
da0555d Adding the first top-level terminus (yaml). It works and is tested, so now it is time to migrate the Facts YAML Terminus to use the <terminus>/<indirection> file structure instead of <indirection>/<terminus>.
0a48e5f Moving the Puppet::Indirector::Terminus class into its own file and adding a spec for it.
7e2ff4b Adding a couple more tests to the indirector, talking about terminus registration. I am about to change how loading is handled, so that individual termini are declared as normal Ruby classes.
7740cd4 The indirector specs now all pass. I think I need to add a few more specs, though.
4e8b671 The unit tests for the newly-resurrected indirection class now work; all we need do is fix the indirector module tests.
8212f88 Fixing all existing spec tests so that they now pass given the redesign that Rick implemented. This was mostly a question of fixing the method names and the mocks.
944cd0e Whitespace and comment commit.
46d6906 An intermediate commit so I can start working on a different branch. The file recursion code actually works for the first time in a painful while, but there are still some quirks and design issues to resolve, particularly around creating implicit resources that then fail (i.e., the behaviour of the create_implicit_resource method in Configuration).
e90a51f More spec and indirector updates.
129cce8 Finally, some progress. Closing the loops and delegating registered class calls out to the actual Terminus.
a6c4041 Reworking the Indirector code. Continuing to fight the classgen and instance_loader "utilities".
9fa2628 This is basically another intermediate commit. I feel like I've gone too far down the rabbit hole to turn back now, but the code is clearly getting more centralized around the Configuration class, which is the goal.
19e0493 Updates to indirection stuffs. Making a better spec and migrating to it.
b3c8cdb Configurations now set a "configuration" instance variable in resources that are inside a configuration, so the resources can interact with the configuration to get things like relationships.
f17f19d The whole system now uses Configuration objects instead of ever converting the Transportable objects into a tree of components and then converting that into a graph. This is a significant step, and drastically simplifies the model of how to use a configuration. The old code might have looked something like this:
f014d73 Partial fix for #772. The SIGHUP now produces a EOPNOTSUPP instead of NameError.
3ccf483 Removing the completely obsolete passwd2puppet and the obsolete component.rb
3632926 Moving the resource container behaviour to the Configuration object, rather than the base PGraph class. I expect I will just do away with PGraph, but for now, I am at least going to keep configuration-related code in that class.
43f22a2 Adding a to_graph method to TransBuckets, so that the buckets can directly generate a graph, rather than having to first convert to RAL types and then have them convert to a graph. This allows us to make it so components do not need a @children array at all. This was all done because I am having the "already a parent of" problem again, and I have gotten far enough that it is relatively easy to just make this problem go away once and for all.
a6fe700 Another intermediate commit. The node and fact classes are now functional and are used instead of the network handlers, which have been removed. There are some failing tests as a result, but I want to get this code committed before I massage the rest of the system to make it work again.
1459c50 Adding setup/teardown hooks to rspec, so we can use test/unit methods
3b3065b Refactoring the feature support so it loads libraries when a feature is asked about, rather than when it is defined.
65c1501 The Node handler is now obsolete. Node searching is handled through the indirector. I have not yet added the tests for the node handlers themselves, which is next.
1638089 Fixed #797. Removed the warning message about specifying 'enable' or 'ensure' when initializing a service.
6f9a444 Fixed #784 by applying patch by vvidic.
5aa4440 Doing an intermediate commit so rick can look at the work I have done so far.
bb69a1f Renaming the instance loader method to "instance_load". It was previously autoload, which could class with Kernel.autoload.
6a105c4 Fixed hdiutil syntax for ticket 812
19a748b Removed TYPE token, replacing it with CLASSREF token, in the grammar and lexer. Updated CLASSREF token regex in the lexer.
ca9c48d Removing extraneous logging from the node handler
041393d Fixed #774, which fixed fully qualified collection statements
6700adc *Finally* fixing the tests that were failing around users and groups. The problem was that the autoload tests were somehow clearing all loaded classes, including the providers. This is fixed now.
9af79f1 Fixing some failed tests. Mostly cleanup. Next is to make all of the user tests pass again, dammit.
50874b2 Fixing a path test. I have now made the path stuff a lot cleaner, but it apparently broke this test.
ca57c79 Fixing #801 -- resources that have changes when running in noop mode do not record that they were checked, so that they will be scheduled on the next run. This is a somewhat murky solution, but considering that no one had submitted this bug before, I expect it will not hit many people.
caad11a Fixing some broken tests in the master client, and adding a test for #800 but it is unfortunately disabled because we cannot realistically fix it using the current design. It will be easy after the REST refactor, though.
7abc78a Fixing #795 -- configuration elements now make sure all file paths are fully qualified by prepending the wd to unqualified path names.
4212f9c Fixing #802 -- tags are now applied before parent classes are evaluated, so parent classes can use tagged() to test if a node is a member of a subclass.
4104bd3 Fixing #807. The exception handling should more closely resemble how it used to be done.
b7f4244 Renaming some ast resource classes and files so they make a lot more sense.
653c151 Fixing #806. Resources correctly look up their fully qualified definition type, just like resource references do, which causes the resource and reference to again agree on the full name of a given defined type.
40e3b37 A small change to the indirector, moving it to a module instead of a class. I still do not really know how i will use it, though.
a5539cd Adding my indirector class before i rewrite it. I am probably not going to keep any of this, but i wanted to store a copy before i got much further.
b0a9475 Flipped the switch so that compiles now return a Configuration instance instead of pre-extracting the configuration.
11b127b Successfully modified all tests and code so that all language tests pass again. This is the majority of the work necessary to make the separate "configuration" object work.
3b2efd2 We now have a real configuration object, as a subclass of GRATR::Digraph, that has a resource graph including resources for the container objects like classes and nodes. It is apparently functional, but I have not gone through all of the other tests to fix them yet. That is next.
0faf76e More refactoring. I have removed a few more extraneous methods from Scope, mostly just pointing directly to the compile, and I have begun (but commented out) the move to having resources to model each of the classes and nodes, in addition to the definitions. This will, again, enable a real Configuration object, and it will enable class versioning and similar features.
9d70b97 Removing the Scope#setresource method, since it was essentially redundant. The work is done in either AST::ResourceDef#evaluate or Compile#store_resource.
b021587 Doing a small amount of refactoring, toward being able to use Parser resources to evaluate classes and nodes, not just definitions. This will hopefully simplify some of the parsing work, and it will enable the use of a Configuration object that more completely models a configuration.
25f6d7c Deleting old documentation that somehow made it back into the tree in the switch to git, and refactoring the evaluate_classes method on the compile object so I can use resources as intermediaries, thus making classes do late-binding evaluation.
62806bb Renaming the file containing all of the configuration defaults to "defaults.rb", since I am going to create a separate "configuration" top-level directory to contain all of the classes related to managing the configuration for a given node.
6832a4b Fixing some failing unit tests.
2625eb1 Making a couple of small bugfixes in the configuration subsystem
1de5ae0 Adding support for providing a diff when files are being changed. Currently uses a local diff binary, but could easily be changed to use the ruby diff/lcs library. Modified puppet and puppetd to automatically show file diffs when in noop mode, but can otherwise be enabled using --show_diff. This only works when running interactively, because the diffs are printed on stdout.
11081ce Multiple environment support now works, and I have even tested it in real life. This commit is mostly a bug-fix commit, resulting from the difference between real-life testing and unit testing.
9ea8e6c The fileserver now uses an environment-specific module path. I also made various bug fixes around the network tree.
51ff72c Adding a bit of testing for node names.
4e9c631 Moving the node tests to rspec, and cleaning up the spec of the node, especially WRT the environment.
a8f2a33 Moving the node tests to rspec, and cleaning up the spec of the node, especially WRT the environment.
9df4fd1 And we have multiple environment support in the parser. The only remaining piece to make this complete is to add multiple environment support to the fileserver. I also renamed Configuration.rb to Compile.rb (that is, I fixed all the classes that used to know it as a configuration).
ba3a861 Removing this test for now; I do not have time to port it from test/unit to rspec
37f0eed Renaming the "configuration" object to "compile", because it is only a transitional object and I want the real "configuration" object to be the thing that I pass from the server to the client; it will be a subclass of GRATR::Digraph.
deb0107 Oops, created a test directory in the main spec dir, rather than in the unit/ subdir
3030d3e Modules are now tested with spec, and they now can handle environment-specific module paths.
ab54183 The config class now has support for add an environment to its search path. Now I just need to go through the whole system and use the search path in addition to the parameter name itself.
c6e201c I have added basic support for a search path, altho not yet with any ability to manipulate it. All config tests pass in both the old tests and the new ones, so it is time to add the hooks for manipulating the search path.
520aaaf Adding some rspec tests for Config.rb, because I am planning on significantly changing its internals and the current tests, I think, will be harder to migrate than just writing rspec tests from scratch.
724fef1 Everything up to the parser (and the Modules) is ready to support multiple environments, including the parser having an environment setting. I have also created my first spec-based tests, for the interpreter (and deleted the old test/unit tests).
3d68ed6 Oops, left out the spec rake file from the main spec commit
58494cc Building a stand-alone spec directory for creating the new spec-based tests.
d59315a Adding the second half of the rspec upgrade -- apparently the "git add" thing I used did not remove the old files, only add the new ones.
5601ecf Upgrading rspec to version 1.0.8. This only includes the contents of the lib directory, and even then only the spec-related stuff, not the autotest stuff.
7c4d39e Adding environment information to the client fact list. The environment is retrieved from the normal Puppet configuration, so it is set via puppet.conf or the cli, rather than being a normal fact.
b599862 Fixing the integration test between interpreter and configuration -- the interpreter was not passing on that the config should use ast nodes
a54fa7e Sync to latest specfile in Fedora
8b3361a The last commits before I actually start on the multi-environment support. There are still failing tests, but apparently only those that are also failing in trunk.
f1727f1 Adding the topscope metadata to the configuration being returned to the client, just like it expects, and fixing how the resource handler calls the master type.
efcd1e8 Fixed CA race condition (#693)
4eb87ed A round of bugfixing. Many more tests now pass -- I think we are largely down to tests that (yay!) fail in trunk.
2a4e101 All language tests now pass. I expect there are other failures elsewhere, but I want to commit this before delving into them. My method for fixing the tests was to do as little as possible, keeping the tests as bad or as good as they were before I started. Mostly this was about changing references to the interpreter into references to the parser (since that is where the new* methods are now for ast containers) and then dealing with the new config object and its relationship to scopes.
6467c21 The first pass where at least all of the snippet tests pass. I have unfortunately had to stop being so assiduous in my rewriting of tests, but I am in too much of a time crunch to do this "right". The basic structure is definitely in place, though, and from here it is a question of making the rest of the tests work and hopefully writing some sufficient new tests, rather than making the code itself work.
a846ea9 The new parser configuration object works now, but the rest of the compiling process is hosed (although the parser itself should still be fine).
282ec89 Fixing the spec library so it correctly can see its version
1527f4a Adding node caching, so that node sources are not spammed during file serving and such
a953954 Keeping the node names in the node object, so that they are available to the interpreter
297dabb Refactoring a small part of the interface between the configuration handler and the interpreter.
901ae68 Requiring mocha in all cases in the test tree
70dffdd The new configuration handler looks to be ready for usage. Now I just need to convert the interpreter to use SimpleNode objects, then continue with the Configuration object.
aabad8e Adding the necessary name/ip fields to the node methods
65559af Adding a "none" node source, which will be the default node source and will just return an empty node.
2ff15c0 Added shortname support to config.rb and refactored addargs
90a9d09 Finalizing the node handler. It now correctly uses the different node sources and knows how to retrieve data from those sources. Now I just need to fix the language stuff to use this handler instead of the existing node stuff.
ec50484 Fixing documentation string on the file "ensure" property to remove the confusing mention of "exists"
58e3855 Added optional per-module lib directory.
aab419b An intermediate commit in the work towards adding multi-environment support.
40491eb Merge /opt/rl/git/puppet
b59d396 Revert "Updating more milestone names"
3e9ac59 Updating more milestone names
ab42534 Applying patch by Adam Jacob to make external node tools able to handle command-line arguments
24e7b4d Revert "Updating more milestone names"
61a747f Updating more milestone names
b5aefd4 Adding milestone names to changelog
7e4f270 Actually honour :namevar => true on newparam calls
01b21ae Removing extraneous debugging from crontab
6ab30eb Fix for setting global exit code ($?) in SUIDManager tests
0195893 Broaden assert_absent so that it thinks that :purged is equivalent to :absent
6a78648 Change the service name so that it is less likely to trip on a common word and spuriously fail
e143cae trac #763: Make redhat provider default for CentOS (patch by jtimberman)
d2f2bc0 Trivial mock cleanups
ada960b Constants in provider/interface/redhat.rb are getting redifined as they are dynamically assigned, changing them to instance variables
8f05951 Changes to lib/ corresponding to test refactoring from r2759, was unaware that subversion only commited in the CWD
13f358d Highlight what I think is a problem in the test suite that I just can't solve
3de4829 Refactor SUIDManager tests to run without root, change SUIDManager's behavior to not silently fail when it's not root and fix all other tests that broke as a result.
5a25701 Upgrade mocha to 0.5.1, which gives much better error messages
5e8d71d Fix the ral:providers:host:parsed tests so they run successfully
9530df1 Updated to version 0.23.2
0d312a1 Updated to version 0.23.2
b84015a The last set of bug-fixes before the next release. This commit just fixes a couple of problems that resulted when I changed the Provider#initialize method to not duplicate its argument, which was necessary for ParsedFile.
aaf5959 Adding test support for the other mongrel configuration header
db0ffc7 Copying the "commands" and "confine" statements to the actual dscl providers, since they need to be there to determine where the providers are suitable. Otherwise base classes could unnecessarily affect how subclasses work.
5e419cf Fixing #749 -- environment settings no longer accumulate. Significantly adding to the cron tests at the same time, such that hopefully we will no longer have these recurring bugs. I now do every combinatorial of multi-line cron jobs, including doing them all in one file. There are, unfortunately, still edge cases, but maybe we will have some peace in cron space for a while, anyway.
d121b1f Removing the code from #745 until it can pass some basic tests
1e6c2ba Adding syslog support by devdas (#745).
22e7b39 Fixing #751 -- the interface providers now have basic tests, at least to verify that prefetching and listing works. I think these resource types need to be largely rewritten, though, and they currently have no relationship to ifconfig, which seems strange.
7bda32e Fixing #731 - we are now correctly only collecting exported resources
3d629bb Fixing #730 -- mounts now call flush() before trying to mount
a8bf96a Adding a file that should have been in a commit from yesterda
40e4d6f Fixing #735 -- gen_config now uses a single heading, matching the name of the process
97cd057 Fixing #314 and #729; here's the changelog:
72f2ac3 Apply fix for typo provided by Toshio Kuratomi (bz250870)
2a37c73 Removed stray debugger method.
5a5d241 DirectoryService provider for users and groups. Alternative to netinfo, as apple has indicated NetInfo may go away at some point in the future. It might happen in October.
08d8945 Fixing #734. The problem was that when I switched how the configs were parsed, I managed to lose the ability to keep values set on the cli from being overridden by values set in config files.
5eacd19 Renaming the linux interface provider to redhat
6841397 Applying patch by stick to the linux interface provider
877282e Undo previous commit, which was an error
81d690a Do not set any options if they aren't set in /etc/sysconfig/puppetmaster - otherwise we clobber settings from puppet.conf
36a3e4a Changes for 0.23.1
52e9fa0 Adding interface implementations, as written by Paul Rose
7547baf Adding a test for rails
1e11a1a Removing test that ended up being redundant
4b25750 Applying patch my emerose to fix #652.
87da172 Adding the requirement that the cert dn have /CN= in it, thus hopefully catching clients without certs
530d290 Applying a modification of the patch from Marcin Owsiany, allowing Mongrel to be a CA
64fba48 Updated to version 0.23.1
d3988cc Updated to version 0.23.1
2229dc1 Fixing #726 -- mounts can now correctly handle mounted but absent filesystems.
47b7058 Adding some code in an attempt to fix #728, but it is all commented out since I could not get it fixed in time for beaker
2e14ea4 Attempting to clean up the mount documentation as in #727.
7401ada Caching whether a given file or module has been loaded, because the loading was greedy and was causing files to get loaded every time a class or module was asked for
3f1b957 Fixing the mail aliases generated by the mailman list provider; it was generating capitalized list names
3f1c865 Fixing #725. I was apparently not deleting the alias I was creating to the components.
55014a2 Hopefully fixing #720 -- I added tests and a lame back-off system to give the child process time to write
eacb06c Converting mount test to use mount everywhere instead of df
501e8c8 Adding the ability to specify relationships to classes, using Class[name] resource references.
b9dd7ee The first round of bug-fixes in preparation for beaker
5d7c5c9 Adding documentation to the "test" script
4f34fb0 Removing the chdir from util.rb, I forgot that the directory often matters
f2a1a10 Hopefully fixing #640, and maybe some warnings at the same time. I added a call to Process.setsid after the fork, and I chdir'd to /.
fdd2d49 Fix #696. (patch by Jason Kohles)
90c8b8c Fixing #716 -- the package type was considering anything that was not "absent" to be installed, but that included "purged", thus the problem
0316bed Applying patch by DavidS to fix #711.
48755b1 Fixing #702, hopefully. As suggested, I switched to "mount" instead of "df" to determine whether an fs is mounted.
f59ce4e Fixing #695 -- resource references will correctly serialize and unserialize in the db
53a469c Fixing #703, mostly. You still cannot do multi-condition queries, but you can at least query against any parameter, and matching any value is sufficient for a match, so the tags work fine.
d5569bc Fixing #719 -- the filebucket docs now only mention filebucket, not pbucket
d9a30a6 Trying to get rid of the warning from #724
e618065 Applying a slightly modified patch by Dean Wilson -- puppetca now exits with a non-zero code when it cannot find certs to clean.
49d8ef2 Guard the rpm command suitability confine better so we hopefully stop seeing all of the 'Command not available' errors
f104dc5 Updating the docs to mention that you can use the file server with no server name
cf25b25 Fixing some logging in cron
60ef578 Fixing the rest of #705, except for the env stuff, which I was not able to reproduce.
53c2f0a Fixing #691 -- I added "refreshable" features to the types that can restart, although exec does not have providers (yet), so I just made the docs a bit clearer
4c1a70c Reordering some of the type docs
e0237d1 Removing notice about "import loop", which was happening constantly when autoloading module files
1d261bf Fixing error message when a parameter is getting redefined
554c23c Adding rpm as a specific command to :rug
54a5f77 Fixing #589
2c13d53 Fixing #468 -- fully qualified resources can now be specified as dependencies
e88d694 Applying patch from #714 -- aptrpm now loads on RHEL
c3290a0 Fixing the mailman provider so it correctly matches case. Apparently mailman helpfully autocapitalizes list names.
2086e07 Removing extraneous debugging
6ddbec3 Fixing the interpreter autoloading so that it correctly loads classes even when being loaded from a namespace
f217fbf Fixing the instances method. It now works when there are already managed resources.
edb1be2 Fixing the :check metaparam so it does not try to check unsupported parameters
f1462cb removing the test for a method I removed yesterday
e98edac Applying docs patch by David Schmitt from #713
7580657 Applying a version of the diff to the defined() docs from David Schmitt
a4b94cf Fixing the first half of #705 -- matching no longer fails. I think this also fixes #648.
d104d4b Having FileType instances automatically back their contents up to a filebucket, so it is much harder to lose content. This does not yet back up crontab contents, though.
17a830d Fixing transactions so that they do not flush resources that are in noop
f570a5f Adding a maillist type, with support for mailman. It is not as flexible as I would like, partially because of how mailman is implemented (the "mailman" command is never in the search path), but at least it is working for mailman on debian.
2d3c920 Adding support for a "mailalias" type, with /etc/aliases support initially. I have not yet figured out how to best rebuild the aliases file when necessary.
fdfe0a3 Adding line/file info to parsing errors in ParsedFile
9f685e6 Adding support in Property for declarating whether a given property type will match all @should values or just the first.
c8801b7 Always setting a to_s value in authstore, so we do not get dumped objects
e79828f Cleaning up a log message in the transaction
20b9060 Adding benchmark info to fact retrieval in the config client
7a71db8 Adding patch by Valentin Vidic to add the "+>" syntax for adding values to parameters
e662c86 Fixing #621 -- plugins are now downloaded directly into the $libdir, and autoload looks for them there. You can now easily download any reloadable file to your clients.
7befe1b Changing some of the internals of autoloading so that there is a class-level method to query whether a given file has been loaded.
eabe0d1 Fixing #710 -- you can now specify the rails_loglevel
d36d0cf Fixing a typo in a log message
8807ac2 Changing "element" to "resource" in the documentation, which just aligns with a terminology change we made almost a year ago.
f5f8949 Changing the log message when a resource type cannot be found
773f187 Ignore the pkg directory if it exists, and fix up a couple of tests that were erroring out, which also will help the confinement of package types a bit more.
1bcca31 Fixing #687.
8a7fe9f Applying patch by David Schmitt from #701.
4080077 The parser now throws an error when a resource reference is created for an unknown type. Also, resource references look up defined types and translate their type accordingly.
07f0519 Making sure that #686 is fixed -- I specifically included the Daemon module in the Puppet mongrel server, and I call daemonize on the Puppet class, rather than the Mongrel http server
e8217ab Hopefully fixing #685 -- I added a wrapper around the call to getconfig(), so any timeouts will just throw an error and skip the run, rather than failing and killing the daemon. This is not the best approach, since really, each method should be wrapped, but it is sufficient.
60e5e10 Applying further tests to double-quoted hostnames by Valentin Vidic
266d37d Applying patch by DavidS from #697 to allow host names to be double quoted
aa74135 Fixing #596 -- classes in modules now autoload
d0680c8 Fixing the dpkg querying so that it works for packages that are in "config-files" state rather than just missing entirely. Also fixing logging so that the package version is visible, instead of a dumped object
8b14ef8 Fixing logging of module mounts; it was using the module as the name, rather than the module name
32e5bff Removing extraneous debugging
3ae3a4e Fixing #689, although I have not added unit tests. The problem was that a tag name was being removed, rather than the tag object itself.
19e180f Fixed #680 puppet should handle internet enabled image files correctly.
c22e667 Applying patch by daikinee from #690. I was not able to reproduce the problems, but it did not seem to hurt anything, either.
50b8f96 Fixing #704 -- Puppet was not failing correctly when schedules were missing, I think
c762c19 Removing the long-obsolete Element base class. The Parameter and Type classes no longer have the same base class.
0ff7827 Fixing #620 - class names and node names now throw an error when they conflict
a627f46 Adding a reference to the LDAPNodes wiki page in the ldapnodes config item
0f4de4f Fix trac #684 - set exit code for status properly (patch by abnormaliti)
6b7d3aa Create the right puppet.conf; make sure old config files get preserved and stay functional
ac36ddd Fix name of main section
ec2d469 Rename puppet.conf to puppetd.conf
8013e96 Get rid of using silly macros in %install
dc2a0bf Use single config file
3aafa84 Updating reference docs
55a512c Updating trac location for laeg
044968f Updating build files to support laeg
ada4355 Updated to version 0.23.0
d8f4c53 Updated to version 0.23.0
049faf8 Updated to version 0.23.0
8844fca Changing the paths to match laeg, instead of culain.
d79a788 Modified the fileserver to cache file information, so that each file isn't being read on every connection. Also, added londo's patch from #678 to avoid reading entire files into memory.
944e1f4 More updates to puppet-test
4bb0228 Updating puppet-test with clearer options around describe and retrieve
fd15de7 Removing extra debugging from the interpreter
5043ade Updating error message during test failure.
e5a9e24 More test fixes. I seem to be getting very close.
bd444d8 Refactoring puppet-test -- it now supports specifying a fork level (so you can get multiple tests running in parallel from one host), and tests are modeled explicitly, so it will be easier to add new tests.
a57e39d Added documentation for pkgdmg provider in the provider desc accessor as per request in #641 It stil might not be crystal clear, but should be better than the one liner it replaces.
01420ac Adding tracing to prefetch failures, and Fixing the environment support in the cron type (#669).
fa39488 The other half of fixing the versionable stuff -- removing "latest" as a requirement.
0b1dbbb Applying patch in #572 by trombik
611e783 Fixing my stupid fix of Matt's work. I conflated :versionable and :upgradeable. I have now added back all of the "has_feature :versionable" lines.
4cb30eb Adding fink package provider.
099bf6c Fixing some failing tests.
f96ec6d Updating the has_version work that Matt did -- the only thing he missed was that the :versionable feature depends on the :latest method, and when that is present we can safely assume that a package is versionable. Also, created the :latest method on the dpkg provider, as requested in #647.
3f6c413 Applying patch by trombik to fix #628.
eb2326d Applying patch by trombik from #624.
2d07334 Modifying the CA server so that it will not send back a cert whose public key does not match the csr. We have been getting a lot of instances of this, so this should cut down that problem.
6e16d9f Fixing #578 -- Invalid certs are no longer written to disk.
bf5d5d5 Fix #657: allow puppet URL's with no server; 'puppet' looks those up on hte local modulepath, whereas 'puppetd' goes to the default server
52f3f83 fixing the appdmg provider to load the package provider base class, and trying to clean up the log-file opening in rails
12adea8 Adding puppetrun as an executable in the gem, along with ralsh (#313).
2ed10d8 updating changelog for #641
bfb3852 Adding appdmg package provider from #641.
f05464e Adding the output_file.close, as wyvern recommended
30ebbc9 Applying the patch by wyvern from #662. This should hopefully kill the client hanging problems.
ac05442 Updating rrdgraph documentation with a pointer to the new rrd package.
029a191 Reverting the change I just made to the config handler; it was only there for testing.
2b1d478 Adding puppet-test, which is useful for performance testing
afc3563 Adding patch by Ghislain from #670, with slight modifications.
f6838f5 Fixing #548, and making functions support other rvalues, too, including other functions.
f842cef Fixing #643 -- replacing the get_posix_field method with a more degenerate version that works even on broken systems
46252b5 All rails and language tests now pass again. All of the rails tests should now be in the rails/ directory, and I have modified resource translation so that it always converts single-member arrays to singe values, which means the rails collection does not need to worry about it.
6084e1a Fixing #673, but I have not written a test case for it. I moved all rails-related unit tests into the rails/ dir, because they keep getting missed.
e8c6cd9 Fixing the yum provider, and fixing the unit tests so the failures people were experiencing will result in failed tests. This fixes #672.
4f7c650 Moving puppetd and puppetmasterd back to bin. Damn. Reverting the fix to #323.
23f986c Move ralsh and filebucket into /usr/bin
659792f Adding ralsh and filebucket to the rpm and the rakefile, and changing the url in the rpm
6be8b21 Modifying the check metaparam so that it just silently ignores metaparams and parameters, since they're uncheckable, and only tries to check properties
e039f7b Fixing the type/title index for mysql
9ba878a Removing erroneous debug message
b5523ff Trying to load ruby gems, in case needed libraries are installed that way, and fixing a warning in the provider
f84ac7d Significantly reworking both external_nodes and ldapnodes support (see changelog).
fc9a798 Fixing error about non-puppet protos
45f76c5 Significantly optimizing the database queries -- I am getting about 40% better times now. See http://www.madstop.com/optimizing_the_activerecord_integration.html.
e32a1bd adjusting the rrd color stack as requested by thijs
469d999 Updated the CHANGELOG.
51b9fc1 Fixing (hopefully) the last two providers that had "resource.is" calls
77934f4 Fixing sun package provider
270cea8 Fixing #644 -- the install.rb file works again
8003320 Applying metrics patch from #659 by thijs
4910301 Fixing a typo in the docs
c67e016 A few small fixes here and there, and the rest of the zones commit
399c37b Fixing #655 -- Solaris zones are again fully functional, from what I can tell
9bc236b Adding indexes for the rails tables
7c53aab Removing the indexes migration, since the indexes are now in the main db schema
ef2698c Updating ralsh with more functionality: You can now perform work on the command line, with commands like "sudo ralsh file /etc/passwd ensure=absent". This makes ralsh a bit more interactive.
cb5bccc Added to_s to the values to ensure the check versus the database will be consistent and booleans and references will check correctly.
d78a7a5 documentation fix
3a2f3d5 Fixing mongrel test so it does not try to load the mongrel server class on machines without mongrel
6aa5d76 Applying patch from #666 by Rainhead and monachus
ea190c1 Changed the host to "eager fetch" all the resources and their associated tables. Also removed some unecessary lines from resource.rb that were causng it to re-read information it already loaded from the db.
3003aad Added the teardown of the database back to the tests.
4442a31 Revert unintentional change.
68e37a9 Major rework of the rails feature. Changed the relationship between host and facts (now many-to-many with fact_name through fact_values). Also changed the relationship between resource and params (similarly many-to-many with param_names through param_values).
c26f678 Fixing #550 -- I had to list pass and dump as optional fields.
f0b5090 Fixing #112 - mounts now default to 0 for dump and pass
d396fd5 Fixing #637 -- defined resources can now correctly be virtual or exported
ad9c9ce Removing old line from the fix for #660 -- I had strangely just commented it out, rather than removing it
ffb7ae0 Fixing #660 by applying patch by freiheit. Looks like this is another problem with yaml on 1.8.1.
79b604d Oops; I forgot to add the base class for package providers. Also, cleaning up the package provider code a touch
c826be9 Adding a simple unit test for mongrel, and adding the ability to select the header used to store the client SSL dn.
b50c85d Fixing error when commands fail -- the error code is now printed, instead of the inspection of it
3479387 Adding (slightly modified) urpmi support from #592 by Devin
73502a7 Finishing off the type/provider interface work, including adding package prefetch for all packages. The only not-done one is yum -- prefetch is set up for rpm, but not yum. We need to modify prefetching so that it also prefetches latest information, to avoid having to run yum so many times.
bf82d51 Fixing the "Server is not a class" problem with mongrel
992636a Applying patches from Valentin Vidic to fix open file discriptor and open port problems
1867d0e Fixing the few test failures that resulted from the changes to provider listing
c35d07b Significantly reworked the type => provider interface with respect to listing existing provider instances. The class method on both class heirarchies has been renamed to 'instances', to start. Providers are now expected to return provider instances, instead of creating resources, and the resource's 'instances' method is expected to find the matching resource, if any, and set the resource's provider appropriately. This *significantly* reduces the reliance on effectively global state (resource references in the resource classes). This global state will go away soon.
a7b057d Adding a "source" attribute to providers, so eventually types will be able to avoid duplication during listing by only listing one provider for each source (e.g., dpkg and aptitude should not both be listed).
0cfd28e this is a spurious commit to test the trac site
e8aef1e Change pi to list properties instead of states
f2c524d Add protect and priority properties; patch provided by Matt Hyclak
0a2b438 Fix trac #601: wrong location for client pidfile
d467e18 Fixing #532 -- reparsing config files no longer throws an exception. The problem only occurred when reparsing a configuration file that was also being managed (which was common) and only whent the manifest was up to date (the combination was uncommon). Reparsing would find the existing file object and use it to check permissions and such, then it would remove all of the internal data in the object, for cleanup; the problem is, the client still had a reference to the object, so when it went to run its configuration, this broken reference was used.
e8097a2 Changing --show-available to --showall, as requisted by Jeremy Dreese on the list
e0fbd41 Switch the package type to use a :versionable feature, and convert all providers to use the feature. Hope it doesn't break anything.
37a221c Add a grammatically correct 'has_feature' alias, and switch to using it where appropriate in existing code
0a605e8 Clean up a really hairy code construct in the useradd provider
58be1fd Fixing up2date name matching, as mentioned by Jeremy Dreese on the list
464e688 Changing the resource title to be text instead of a string, because some title are > 255 chars
48ec137 Mark all package providers that don't currently report themselves as being versionable as not supporting versioning; this way we get a more sensible error message when people try to specify a package version. See #647 for some discussion.
a9ea3c8 Correct a problem with the dpkg provider's handling of the :purged state, and expand the package type's understanding of what purged actually means. Fixes #644
d1458bd Adding a warning for when no properties are specified on services
1883b8f Adding a debug statement describing why restarts are skipped on services
ca255b9 fixing the method to check for hostdir writability in the rrdgraph report
ac686e8 Changing the location of the classes.txt to the state dir
25d5ebd Adding more detail to the per-host reports dirs, since it was not setting mode or ownership.
62a4d4c Adding better error reporting on unmatched brackets -- you will now get notification of what was expected in most cases
2b372df Updating the exec docs to specify that the timeout is in seconds
4aef0ba Fixing #323 -- puppetd and puppetmasterd are now in sbin; packages still need to be fixed
6f83d4d Fixing #501 -- there is now a splay option, disabled by default and when running under --test
7d1f760 Adding the execute bit to install.rb and fixing #473 -- there was a /win/ regex that matched darwin but was just supposed to match windows
611f88a fixing a documentation bug
df6f41a Changing the notify type so that it always uses the loglevel for logging
ef1a4af Fixing #568
e8d560e Fixing #566 -- definitions, tags, and classes can now be single characters
eed85f4 Adding #629 -- an undef keyword now exists
8410c4d Fixing #507 (behaviour in cycles) by changing the topsort algorithm.
67ee251 Using the method for retrieving the dipper class, in case it has not been loaded
e3b7a54 Making sure there is an editor set for ralsh
e95734b Redoing autoload a bit in preparation for adding a plugindir
dbedcd7 A round of fixes so unit tests pass; most of the failures were from the merging of the transaction-refactor branch
28f7d6c Fixing #569 - I have added a dynamic facts option to choose which facts will be ignored.
d9f6f41 Fixing the "is" related problems in yum and rpm support, but there are still some package providers that use the "is" method (grep for "\.is[^_a-zA-Z]" in the package providers), and the util/posix.rb module has a call to obj.is. I will fix those soon.
1934f2b Removing obsolete parsedtype
61784ed Attempting to fix the fact that the yum package provider calls [] on the ensure property, and making the resulting error more readable
85fef63 fixing some problems with the config timeout -- I am not sure it ever actually worked
27cabf2 Fixing a weird bug that occurred because I was changing @parentclass in the AST stuff the first time it was called, from a string to a the actual instance of the parent. This worked fine as long as the parentclass was only called when parsing was complete, such as during evaluation, but if anything resulted in it being called earlier (e.g., attempting to add to the class during parsing), then things behaved, um, badly. This commit fixes the method so that the variable is not modified; there is now @parentclass and @parentobj.
613c413 Fixing a path problem that resulted from the changes I made to internal variable names -- the pathbuilder method in file referred to @resource instead of @parent
aed12c3 Use @http in store, add filterhost
19af1cb First try at the REST config_store
12e5656 Initial configuration storage abstraction layer stuff.
426330c Updated the CHANGELOG with changes for retrieve and acts_as_taggable.
24b11b5 Removed acts_as_taggable from the rails stuff. I haven't removed the tables from the schema nor the indexes yet.
ca2b9e6 Not parsing old versions of puppet.conf -- otherwise, puppet parses the whole configuration.
eca5510 Fixing the to_trans method and ralsh a bit so ralsh now works with the new lack of "is" method
55666a5 correcting some of the function reference docs
1d23013 Fixing #605 -- providers now refer to @resource or @resource_type.
de21226 Fixing #607 -- parameters and properties now refer to a @resource rather than a @parent. The @parent parameter is still set for now, for backward compatibility.
3e7d44e Fixing #606 -- now only components mention @children.
13c7f2f Allow Darwin to remount rather than unmount / mount, as per puppet-users discussion "mount type and ensure => present on OS X" (Message-Id: <C44C8E86-DF31-4344-9B74-937325A03F5F@madstop.com>)
7f8a903 Getting rid of the last vestiges of the logger tests
bfc0c35 The TODO file has never really meant anything, and it hasn't been modified in 2.5 years
cdd0dd3 Adding default provider info to the providers report
2fa529e Fixing the ability to fail correctly in the fileserver -- a constant was not defined correctly for it
fbfaa0f Removed FIXARB's from the pfile stuff. These have been resolved.
93cbe77 Removed FIXARB's from a file that will be going away.
a966606 Removed override of change_to_s since it is the same as the overridden method in EnsureProperty.
8bad074 Removed override of change_to_s since it is the same as the overridden method in EnsureProperty.
b0374d8 Removed calls to is.
5b44159 Removed the testing method: checknewinsync.
c164360 Merging of refactor-transacton to the trunk. This work removes the :is attribute from properties and relies on the provider to cache or return the current value of the property.
8f18746 Hopefully final version of the providers reference
c99e99d Intermediate commit of more reference work, including making provider suitable more introspectable. I am about to significantly change the output format of the providers reference, so i want to get this committed before that change.
73df973 The result of .compact.join("\n") isn't assigned to anything. Fix.
568db0b Fixing configprint so it fails correctly when an invalid parameter is provided, rather than throwing a stack trace
40b3834 Sorting the network handlers in the network reference
7835d29 Adding a dynamic? option for references, so those are not stored in trac
1decfa3 Lots of work related to generating more reference. Moving all of the individual references out of puppetdoc and into an external "reference" class, which itself can autoload, so it is now easy to add new types of references. Also adding a network reference, along with an unfinished provider reference.
69cb721 Removing the obsolete logger network interface
a040bd4 First run at moving references to lib/puppet instead of puppetdoc
f42a755 Adding a module to abstract using Autoload to load and manage instances
53f1612 Fixing the time-cleaning in the rrdgraph report
494675b Fixing #206 and #422. Executables will still look for the deprecated config files and load them using the old parse method, but they now prefer a single configuration file, and files can set parameters (owner, mode, group) in brackets on the same line.
1f8de9d Consolidating all of the configuration parameter declarations into configuration, at least partially just because then the docs for each parameter have to be a bit better. Also, I have gotten rid of the "puppet" section, replacing it with "main", and changed, added, or removed a couple of other sections. In general, we should now prefer more sections, rather than fewer.
f783859 Correcting function reference markup
e864eab Applying patch to puppetrun docs from JosB
e1438a5 adding --summarize option to the changelog
28254b5 Adding a --summarize option, to get a transaction summary
0c07125 Fixing #615 (subclasses with similar names) by getting rid of the class "type" and "fqname", and instead using "classname" everywhere. You should no longer see unqualified class/definition names anywhere. Also, rewriting how snippet tests work, to avoid creating all of the files, since the point was the parsing tests, not functional tests.
8d7ec14 Adding a fact handler, along with an abstract interface for fact stores and a simple yaml fact store, towards the Node Classification work.
79dcd33 Set LANG/LC_ALL/LC_MESSAGES/LANGUAGE to 'C' whenever we execute things, so that the output that comes back is more easily parsed, without needing to understand all sorts of foreign languages
a1d4f35 Update to latest shipped for Fedora/RHEL
4022968 Committing all the work that josb did, plus a couple of small changes
bf37676 Applying patch to puppetd from Jos Backus
8d11bb8 Fixing class name for Handler in puppetd
1ccdff5 Adding --serve back in as an option to puppetd, and failing when a handler is specified but missing
fb4f04d updating changelog with version number
0f02a54 Updated to version 0.22.4
e049999 Updated to version 0.22.4
4f2b903 Updated to version 0.22.4
3e895b5 Changing the remount stuff back to not repeating the mount options.
6438270 Adding a "supports_parameter?" method to test whether a given provider supports the features required by a given parameter. This is used during attribute instance creation, but its creation was necessicated by test code.
c9de332 Fixing the fileserver naming tests after the change to allow "-" in fileserver module names.
80ec494 Fixing #430 (I hope) -- execs now autorequire the specified user
483c25e Switching the simpler features to a single file, so it is easier to add new features
c369c6a Fixing cron to correctly match blank lines, fixing #602
f69dcda Working a little bit on rails failures, with no real progress
e05392e Fixing a bug in the tests introduced a while back when I switched to using "generate_report"
7fb7146 Updating the changelog for #594
3aafd81 Fixing #594 -- Files on the local machine but not remote machine now purge. Note that this introduces a difference in behaviour between recursing locally and recursing remotely.
c2bc848 Adding purge => true to downloading of facts and plugins, and removing some extraneous logging from the provider base class
7e97143 Allowing "-" in fileserver module names, #617
4dbcc5d Changing the resource handler to return the whole object, rather than just type and title
8b60d20 Not stripping domain info from the ldap node, as requested
63e907c Switching the mount command to always add the mount options, so that the parsed provider can be used even in cases where /etc/fstab is ignored, like it is on OS X.
dad9373 Fixing the tests for the aptrpm provider.
89ac6d7 Adding "rug" package provider from #609
4296e4e I managed to put those provider tests in the wrong file -- the file meant to test the resource type interactions with providers, rather than the provider file. Fixing that, and the failed test resulting from that silly mistake.
21eab22 Okay, one last try -- the Util#binary command was not returning a path in all true cases, and the provider tests were poorly written and missed it.
94bd3b2 Apparently I messed up providers a bit; binaries were not having their full paths returned, which made most providers suddenly unsuitable. This fixes that, and adds tests to verify behaviour.
96eed99 Closing #585 -- providers can now have optional commands, which only differ from normal commands in that they do not affect a provider's suitability
0a46bb2 Fixing #603 -- I had to add a special case for escaped carriage returns. I am not entirely sure this is the right solution, but so be it.
9a1a88c Fixing #574; puppetmasterd now exits with non-zero error code when there is a failure
3169bfa Adding extra info to the "Parameter already set" error, as requested in #573
86c206b Possibly adding the ability to manage passwords on os x. I expect it does not work, since there is probably no way to set up an encrypted password, but at least it now creates a user that can not log in by default.
0aeda97 Adding the ability to manage passwords with the useradd provider
7fbd3ff Adding the ability for parameters to declare that they require a given feature, and resources will not instantiate that parameter if required features are missing. This is mostly useful for properties.
4aaae62 Adding a note to the references indicating that they are autogenerated.
0681cfa Refactoring puppetdoc so it is a bit cleaner and is actually object-oriented. PDF output still fails miserably (there has to be some kind of markup problem, but I have no idea what), but other output now successfully varies on the pages.
0ff3772 Last modifications to rst conversion before bedtime
1d036bb All conversions to RST are done, but I did not quite succeed at making puppetdoc able to generate a single PDF with all of the references in them.
9526e53 Mostly done with the conversion to restructured text, but there are still some tweaks to perform on the typedocs output.
8d3673d Adding a :block_eval option to FileRecords in FileParsing, so ParsedFile providers can have records just define a bunch of methods at once, rather than using lots of hooks. This is cleaner when custom parse and generate methods are used.
a478ed2 Translating all of the docs except the type docs to RST
70ec0cc Removing the naming restrictions on cron names
5afa587 Fixing #588 - the parser correctly ignores directories in globbing now
3c5ba06 Fixing #587 -- just defaulting to root when there is no USER set in the environment.
e1b0444 Fixing #591 -- puppetd now correctly restarts itself when it receives a HUP
37ffb63 Removing the stubs for nodevar; I did not mean to commit them
7cc3a2f adding note about the class variables in the change log
5436f96 Enhancing the docs a bit for the apple package provider.
775c72b Adding support for aptrpm from #227 as added by Ian Burrell, the rest of the commit
be68411 Adding support for aptrpm from #227 as added by Ian Burrell
f1f4c42 Adding patch by apowers from #545.
df0cd95 Adding init script by apowerrs from #546.
9828b25 Fixing fileserver doc links
f8a0e99 Adding the functionality requested in http://mail.madstop.com/pipermail/puppet-users/2007-April/002398.html . You can now retrieve qualified variables by specifying the full class path.
9946249 Only caching the configuration when it has been successfully turned into Puppet objects
b6d0d27 Adding a --version argument to puppetca
da4d252 Changing the test package for debian
b8b14d3 Forgot to change Puppet::Util::SUIDManager#run_and_capture arguments to execute
efe9a83 Fix for #565: Final merge of changes from source:branches/execute-refactor into source:trunk Generated with svn merge -r 2378:HEAD https://reductivelabs.com/svn/puppet/branches/execute-refactor trunk
8ab2722 Hah! Finally fixing the problem where mount tests would fail when run as part of the whole suite. The real problem was that I was changing the filetype of the provider without setting it to change back after the test, but the key change that made it straightforward to fix this problem was that my test loader was not exiting with a non-zero code when there was a failure, which mean that the ./test script never thought anything failed. I fixed the former, then fixed the test script to work fine with -n method_name stuff, and quickly found the problem. *whew*
f9d89b5 Changing the date that certs are valid to start one day before the cert is created, so clocks that are off by a little bit can still be used.
4615e3a Fixing Client.read_cert so that it automatically adds the certificate information to the driver when the certificate is correctly read. This makes sure the Net::Http instance has the cert all set up.
ca5d068 Updating the docs for the sourceselect parameter
295b357 Renaming some methods so that we can generate a report on a transaction and then retrieve it later
1e8e7ee Fixing #567. I overrode the propertychanges method to only return changes if the file exists or if the file has a property that could create the file.
4863012 Enhancing the report docs a bit
0ecb775 Adding last bits to the change log for 0.22.3
a999752 Updated to version 0.22.3
24ad5ab Updated to version 0.22.3
9ce7c79 Updated to version 0.22.3
e154589 Fixing puppetdoc with the recent changes to the networking code
801d0f7 Fixing a bug I apparently introduced in the testing that would have made user management not work with netinfo. In the process, I am enabling validation on the nameservice subclasses.
2544f75 Fixing the documentation to match reality, as reported in #548.
4358e85 Trying to fix the problem that occurs when noop somehow manages to be nil when downloading files
2ad9469 Changing gems to automatically include dependencies
858cb81 Updating changelog and adding filebucket to the exluded file list in the Rakefile
d54b645 Updating changelog and adding filebucket to the exluded file list in the Rakefile
fa26552 Fixing #562; I had to fix how the client class was loaded
142d0fa Applying patch by Ian Burrell from #559
2c3abbe Refactoring some of the rails code. The speed is now pretty good, but the tagging stuff does not seem to be working and is certainly working very ineffficiently. Blake says he is going to take a look at that.
33f4a66 Renaming pbucket to filebucket
52df47e Finalizing the filebucket client, with test code.
def15e3 Adding filebucket client app
c5e1a44 Fixing the "readcert" method after getting the signed cert; the method got refactored, and essentially renamed in the process
60d36e2 Moving the authconfig setting to configuration.rb instead of network/authconfig.rb, as mentioned by Koen Vereeken
5bd0e8c Rails is now significantly faster. I refactored all of the queries; they are mostly reduced to three queries, each of which is relatively fast, although there are still a ton of file- and tag-related queries that I cannot find the source of. Note that this speedup requires indexes, which will only get added if you start puppetmasterd with --dbmigrate (although you cannot always start with that, as there is an error in the init code). I expect that the indexes will not help unless you forcibly reindex your database, but after that you should see significant speed improvements.
4c357d8 Adding a migration to create indexes
5ad9bf4 Fixing #553; -M is no longer added when home directories are managed
804c0f4 Fixing the same bug as the Metric stuff, but for logs this time.
46152c1 Fixing the Metric class old clients can still refer to the Puppet::Metric class.
36feb29 Fixing a small bug in testing whether instance methods are already defined.
45904ca Updated to version 0.22.2
0452878 Updated to version 0.22.2
474b86c Hopefully the last batch of commits before I release 0.22.2. Mostly just get tests to pass.
90d8b2d Remove no-lockdir patch. Clean changelog
a68a7c2 Change puppet's homedir to /var/lib/puppet
145c39c Don't clobber an explicitly given waitforcert
41e1285 Reverting changeset [2243]; this apparently causes chkconfig not to work
bcc937a Absolutely guaranteeing that the provider is always created before anything else. Previously, it could get created later if it were using a default.
60ea7d2 Fixing #432 - you can now manage home dirs with users. You cannot yet purge home directories, because there is still controversy over how that should be done. Also, allowdupe is now handled like a feature, which is, um, better.
3d17685 Adding a "has_feature" method, so a provider can just declare that it has a given feature
290ad14 Finally fixing #504, I think; I even have tests to prove it. It was a little thing, in the end.
32662cb cleaning up an error message a bit
9b5833a Clarifying the errors a bit when nodes come from external sources.
1f8b768 Apply patch from Ian Burrel (trac #479)
3e2510f Adding the "ralsh" executable (formerly known as x2puppet).
531136e Updating the config generation stuff a bit, mostly just cleanup, but also changing the servername fact to be the fqdn of the server.
0153a06 Changing the config cache location to the state dir
f046067 Adding context to the warning message about unknown escapes
0040edf Changing execution to reopen stdin to /dev/null
b804573 Changing notify to default to its message being its name
e2c5dbb Another round of bug-fixes, prompted by test logs from David Schmitt
92bad78 Fixing the spelling of David Schmitt's name and giving credit to Chris McEniry in the changelog.
547fb64 Adding a provider feature table to the provider feature docs
5b2ffbc Adding provider features. Woot!
80dac92 Following Russ Allbery's advice and using the Candidate field in the apt-cache output. Apparently I'm blind.
3606482 Updating changelog for #487
4dc7233 Fixing #487. I know use "apt-cache policy", instead of apt-cache showpkg, because it clearly shows which version will be installed. This is basically impossible to test well, so I just added a test that verifies we always get a value back, although I cannot really test that it is the "right" value. Also, I modified the logging of packages so if there is a latest version, you will get the new version number, along with the old, in the log.
973f9d0 Taking another crack at #504 -- I was using Pidlock incorrectly. I should have been using "locked?" but was using "lock".
cef41c2 A slight fix for #507. This should at least provide better information if this problem crops up, although I cannot reproduce it.
1778883 Changing the "found a bug" message to something a bit more informative.
184266d Fixing #447 - filebuckets now use deeply nested paths
b436002 Oops. Fixing the other tests to now past the facts to "fresh?", as required by the fact checking.
61b3490 Fixing the fact caching so that facts are only downloaded and retrieved once, rather than once during fresh checking and once during config compile.
5f7ae35 Fixing #519. The facts are now cached in the state file and changes to them force a recompile.
a2a9d93 Fixing #544 -- there is now an --ignoreimport option for commit hooks.
a212ea7 Adding #539. Definitions can now have titles, and both $title and $name are guaranteed to be set within any definition.
90bdc33 Adding test to make sure ensure does not conflict with any of the creating types.
e952029 Adding #541. There is now a "generate" function.
6654661 Fixing #538. There is now a simple file() function to read in file contents.
5ecfd39 Looks like I already accidentally committed the switch from using system() to exec(). I am hoping this will fix the many problems people are having with processes hanging around (e.g., #509). This change just removes the attempts at closing TCPServer instances, which should now be fixed from using exec instead of system.
6b85962 The first round of fixes for failing tests.
8eddd4b More work on #542 -- services in noop now produce noop events so that they can themselves trigger further changes
2fe9998 Removing bogus log message in file parsing
3b8dc6a Removing the cycle checks from the splice! method in pgraph, which *considerably* speeds up splicing of very large graphs.
adedab1 Getting rid of a warning in the rpm provider
40eeadb Adding example cron tab from #492 and making the read/write tests ignore whitespace. This cron now parses successfully, as I thought it would with the move to providers.
2a3f56c Fixing #529 -- specified targets keep their values. The problem was that I was using model[:target] instead of model.should(:target) and model.is(:target). The real problem was that my tests were using a parameter for tests but all of the real code uses properties.
fe2f0d9 Fixing #533 -- puppetd now exits in onetime mode.
5257837 Fixing #491 -- the client correctly realizes when the cache file is missing and only considers the config to be in sync if that is not the case.
a76afb7 Trying to clean up the error message from #490. It looks like the problem is just a failure in one of the types, and it has nothing to do with the state file.
4a6d705 Fixing #542. Transactions now cause services to warn when they would have gotten restarted by a noop resource. Also fixing #549 -- transactions now only refuse to delete required resources if they are being purged. All other resources can be deleted just fine.
8387d48 Fixing #540. I modified Puppet::Network::Client::Master so that it disables noop during its run, so that facts and plugins will always be downloaded.
86c63ce Fixing cron support (I hope). It now uses providers, and seems to work, at least on my os x box.
ba23a5a Adding spec libs, so we can use them some day
8ea6ada Clarifying that the ruby RRD support is provided by a binary library
df4595e Significantly reworking the internals of the fileparsing code. It now passes around an instance of a FileRecord, rather than just a hash, which I think makes it much easier to understand.
b05ae2a Don't blow up when PUPPETLIB isn't set
0fa3c43 Search manifests first within modules, and if no module is found, search in the directory the current manifest is in.
38975de Introduces a new implicit 'modules' fileserver module, whose allow/deny can be set from the fileserver.conf, but whose path is ignored and can therefore not be used directly in puppet:// URL's.
ebcb6b6 The template function now tries to first find a template within a module (if the template path looks like it belongs to a module) and only when that fails looks for it in templatedir
ba6257c The basic plumbing for modules: a modulepath config parameter, and a new class Puppet::Module that will contain the module-related functionality. The modulepath can be extended by setting the environment variable PUPPETLIB
10d6891 Adding support for a prefetch hook on individual providers, rather than only supporting it for the whole class.
4fa8008 Fixing a few of the log messages so file content changes always include the md5 sum
6ad8998 Adding a bit more testing to the config stuff
3489bd8 One last try at getting the config and mode stuff working. The tests were passing because "mode" is a valid config option in the tests, but not in the real configuration. So, now the Config class correctly only tries to set the meta params if they are valid options, otherwise they get skipped.
b36f9c9 Fixing the config path to use Puppet[:name] rather than Puppet.name
6b92c04 Oops, forgot a file in the commit
f59cade Fixing a bug related to link recursion that caused link directories to always be considered out of sync.
b6df336 Looks like [2265] was not a complete solution -- it resulted in failures when the config set modes via integers. Everything is working now, and tested more completely.
0925fb0 Adding some more testing on the @should values for :groups on users, and fixing a bug that often made :groups think it was out of sync.
333842b Putting the final touches on #144, most of which I had provided in the mongrel work.
fa253b5 Fixing #489. I was unnecessarily converting to octal in config.rb
69338da Adding some changelog info for the next release, which is still a ways away, probably.
205bbb9 Flushing out the ability to have a stand-alone CA server, specified using ca_server and ca_port. This is just a final unit test, since the code was done and lutter fixed the rest in [2261].
185a003 Fixing #531 and #414. This includes pretty much a complete redesign of the AuthStore class, with (hopefully) all of the edge cases removed, the code is now much cleaner, the tests are (I think) complete, and everything is just generally better.
fde8b28 Fix typo in default config and add simple test to check default config sanity
7e41d43 Turning a failure into an error when, for some reason, pfiles do not have paths set.
46d344b Merging the webserver_portability branch from version 2182 to version 2258.
6823370 Sync with latest Fedora specfile
4a73da3 Don't include bin/pi in distributed tarball (and hence fix trac #471)
1808c50 Apparently the include function was not failing when it could not find asked-for classes. Now it does.
521606b Allowing trailing commas in selectors
9080686 Committing patch by Dennis Jacobfeuerborn to only use the domain name if it is set.
17c59f8 Adding "ignorecache" option to always force a recompile of the configuration
ebc4dd2 Fixing #464 and #515.
ff9ec47 Applying patch in #528 by ask.
cc26026 Fixing #467. It is a hackish solution, because I just reordered the definition of the params, but it works for now, anyway.
d229d49 Fixing at least part of #514. This does not get rid of all errors, but at least it fixes the spurious warning
be8dfd9 Fixing a problem with the splice! method on the graphing. The problem was another issue with hash ordering, where it would usually work but sometimes start failing. The solution was to splice the containers in topological-sort order.
4df0738 Applying a modified form of the patch by cstorey from #523. The modifications were mostly around the fact that Strscan does not set $1 and its ilk.
0f16bf3 Fixing #526. Implemented as a period of "never", rather than adding a new parameter.
07fce23 Fixing #477. setvar() can now accept the file and line info from callers.
d5444e0 Fixing #199 and moving service tests (which are completely atrocious) around.
7d965ae Applying patch by cstorey from #521
36ae6a2 Making the package provider tests able to be executed separately, and using "clear" instead of resetting @objects in the types.
b7a0fb4 Make up2date the default for RHEL <= 4, and confine it to RHEL; make yum the default for RHEL >= 5. Fixes trac #478
672e281 Fixing #142. As expected, trivial.
87f100a Applying patch by DavidS from #522, along with test code and a small bit of code cleanup.
a3f3674 Redoing some aspects of the graphing in hopes of helping hte performance a bit.
1a7d8b6 Fixing file backup defaults to correctly use the puppet filebucket by default.
d833c3e Changing the log messages for source and content properties to mention the md5 sum of the new content
789b786 More code related to #517. Oops.
4c885b7 Fixing #517 and more. Classes now support more than one namespace in their search path, parent classes automatically have their namespaces added to subclass namespaces, and (huzzah) there is a "search" function that can be used to add new namespaces into their search path.
aad5123 Fixing #524. Functions, both statements and rvalues, now support no arguments as long as you use parens.
3e13e36 Actually commit the changes to lib/puppet that were supposed to be part of [2223] (Fuck svn and it's partial-repository-by-default behaviour)
1d711dc Partially complete #241. Add a 'purged' value for Package.ensure, and add a handler for all of the Debian providers. Also wrote sensible test cases, and so we've now got Mocha running around in our source tree.
a752eb2 Fix #516, 'Cached manifests get unescaped twice'
db8a23e Print stacktrace in debug mode when catchign a signal - useful for understanding client hangs
fa02d67 Fixing #472. Apparently this has been broken since I did the parser redesign. I had to fix the scope trees so that subclass scopes are subscopes of the parent scopes, which used to be the case but was far more complicated.
d145aae Fixing #505, #508, and #513.
774415b Allow 'key=' to be the only thing on a line (livna uses this)
4d02823 I believe this fixes the issues in ticket #469 My testing on mysql shows connections being reaped.
7a9e28a Applying patch from #495.
6fbd5fd Removing extraneous debugging
90b1058 Fixing a problem in collecting exported resources. Virtual resources worked fine, but exported resources resulted in an essentially infinite loop.
deab3a0 Fixing the default dbadapter back to sqlite3
3d093ae Applying patch from #510 by curzonj. Note that the right solution to this problem is to use the ruby API, but it does not appear to be stable yet.
65599af Re-add the files
beb7873 Undo the param_name param_value merge
f4f555d Renamed Puppet.name to Puppet.execname so rails 1.2 doesn't freak out
9a672ec Undo the param_names param_values changes
8b18fdf Undo the params & facts stuff
9fe8905 Changing date to datetime in the database
964c805 Trying to fix problem of locks lying around
2418e4a Adding hook to update timestamp when a report is run
0aa3b66 Change Puppet.name to Puppet.execname so rails 1.2 won't freak out.
6555dad Update relationships Remove dynamic class generation for now. Include the fact class
328e576 Revamping collections to get what is hopefully more reasonable behaviour when they are used in combination with defined resource types. You should now be able to combine them in just about any way and get "correct" behaviour, which in this case means that you can have virtual definitions or definitions wrapping virtual resources and the resources will still all get realized.
69d4bfe This works for me. Probably not the most universal fix.
9de665c Apparently using "gem" requires an environment we don't have.
91991f1 Merge fact_names & fact_values, and param_names & param_values.
0b5600a Fixing features to use the new feature location
17a5f4c Applying patch from #502 by Jose
6216ae5 Applying patch from #497 by Jose Gonzalez
258651c Applying patch by Jeff McCune from #496
9cd2636 Applying patch from #474 by David Schmitt.
4effff4 Fixing #482.
c3b6232 Fixing #493.
81ae397 Applying doc patch from #494.
1756bec Fixing #484. Moving unit tests at the same time.
a216df2 Okay, last file moves for the night. The test code has been moved to match the lib directory, and I have moved a couple of things into network/ instead of network/server, since they did not belong as much.
7e07e3d Moving all of the client and server code into a single network/ directory. In other words, more code structure cleanup.
6d8068e Moving some of the stand-alone classes into the util/ subdirectory, to clean up the top-level namespace a bit. This is a lot of file modifications, but most of them just change class names and file paths.
1626023 Adding a libdir setting for puppet, so you can store your modifications to puppet in a separate directory. This probably will still be somewhat limited because it will always depend somewhat on load order. For instance, if you add a new provider, it might not be available when you expect, since providers are all loaded as soon as a type is loaded, which might happen before the libdir is set. It should always work fine if you do not override it, but if you do override it, things might behave a bit strange.
99c8a54 Adding a parameter to allow you to override how an exec refreshes itself.
dd71a51 Changing exec so that the checks apply to whether an exec is refreshed.
31c9a6f Disabling the netinfo mount provider
ad359f3 Reorganizing some of the tests.
d403131 Merging the state-rename branch. This includes the diff from version 2156 to 2168. All states should now be properties, with backward compatibility for the types that restricted themselves to the methods.
f6f72f2 fixing the cookbook link fix
3a024d7 Removing the default value for :ensure on mounts.
71346e9 changing the cookbook link
f80bd5e Fixing exec so it actually works when path is specified as an array
d117aa8 Updated to version 0.22.1
1e90209 Updated to version 0.22.1
463d3a8 Updated to version 0.22.1
1d059b0 Fixing #470, I think. I basically just threw away the validation and let suidmanager do it all when running commands.
69a07b1 The resolve functionality in "test" is almost working...
42d15fe Adding note about removing mounts netinfo provider
2c79bbf Oops, that last commit seems to have broken the rakefile. Works again.
3836201 Trying to get the functionality I had in previous tests. Mostly I want to be able to load many files but run just a couple of methods, which test/unit supports via -n, selectively enabling -d. I now can do this with the Rakefile, using 'TESTOPTS="-n <method> -d" rake <blah>, although I find that a bit kludgy (certainly more so than 'rake -n <blah> -d <blah>').
fd2982f Fixing executable tests to take new rundir into account
a62fd3e Filenames for test must _end_ with '.rb'
12bf816 Fix to make running tests work in ruby 1.8.5
18eebaf Fixing selector tests to get rid of a lame hash ordering bug in the tests.
a3a85d8 fixing rails test to take into account the fact that resources now do not always return arrays
f1deaa8 Fixing autogen so it passes on non-Darwin systems.
173f5cc Fixing a purging bug introduced by [2138]. I had to move the purge check to the recurse method, rather than the localrecurse method, because the purge check needs to happen after sourcerecurse.
62ab873 Deleting the file even if a source is specified, as mentioned by Robert Nickel.
c8f38b7 Renaming "pelement" to "resource". The old name is a holdover from before we had settled on "resource" as a term.
ea73cdb Fixing Files to work with the Resource server. Basically I just remove the "target" value if it is a nullop, so that it does not cause a conflict with "contents" on the far side.
d7fde42 Adding explicit umasks to these tests.
a4de59c Fixing rundir so that it is only set to be in /var if the process is named puppetd or puppetmasterd. Otherwise the unit tests set it to /var/run/puppet, which has the chance to cause hangs.
9dc6cf6 Removing all remnants of the old symlink type
7889b0b Revert 2125, and instead change the way the 'latest' version is selected from the sorted list of versions
97583b4 Updating changelog for 0.22.1, although I am not quite ready to commit yet.
8d90e56 Puppet can now read files on stdin. This means you can put "#!/usr/bin/env puppet" in the first line of a puppet manifest and then execute the manifest normally. Yay!
8821300 Providing a partial fix for #428. Resources can now be deleted as long as all of their dependencies are also being deleted. This, combined with the fix to #433, means that you can now explicitly specify the order of deletion, and everything will work as long as all required objects are being removed, too.
0a62369 Partially fixing #460, take 3 -- fully-qualified classes can now be included.
788a74e Partially fixing #460, take 2 -- fully-qualified definitions can now be used.
a7bd786 Partially fixing #460 -- fully-qualified class names can be used as parent classes.
c9e7699 Fixing #462. The package sort order was always resulting in the lowest-version package being first, rather than highest, so I inverted the sort order.
add6e5d Applying patch in #465.
1f9ede2 fixing #427. Facts now timeout, both in loading and downloading
049d79c splitting the tagmail report into multiple methods and adding test code
727672f Not creating the listening server at all if --onetime is enabled.
af3863e Fixing #440, albeit with a slightly hackish fix.
01ec5ba Moving code from external sources into an external/ directory
1374e4e Moving the switch that disables the certificate authority into the main library, so they can be disabled in the configuration file.
dc580cf Fixing #433. I basically just added checks to all the places where I add edges, to make sure automatic relationships lose out to explicit ones.
e418691 Fixing the warning message related to namespaceauth.conf
d3fc49d Fixing a problem that occurs when puppetd starts with an up-to-date configuration -- the default schedules and filebucket were not being created.
6c61f0c Fixing #463. I redid all the autogen stuff so it can handle autogenerating string values for stupid os x.
8198e7e pointing documentation to the wiki now
54c458c Fixing #438.
04017b3 Fixing #444. I was losing the list of sources when creating new children.
b7560d5 A couple small bug-fixes
3aff4a0 Doing more work on #113. Mostly, just making sure remounts do not happen spuriously very often. They will still have extra remounts when changing the value of "ensure", but that is not currently avoidable (similar to #199).
1cc8ecb Fixing info around newtype options
dd502db Fixing #113. I added support in the transaction for self-refreshing, which just creates a special trigger for resources that have self-refreshing enabled. Logging is a bit different for them, so it is clear why they are refreshing. I still need to verify the remount methods work in the providers.
bf46e7d Adding a "self_refresh" option, so resources can refresh themselves if they have changed in the current transaction.
1f41c35 Fixing #454.
c07494f Fixing #441.
9924244 Fixing #431. Collection was always returning an array, even when only a single value was passed.
0a9c8da Changing how transactions check whether a resource is being deleted. This is a small step towards fixing #428.
f6a3d94 Fixing #455. A simple fix, fortunately.
81025d1 hoo
e29ef5c Updating reference docs
af4f7d7 Fixing documentation references to refer to the wiki
37acfb9 Fixing #442. You can now do: defined(File[...]) to see if a resource is defined.
2db6878 Fixing #434.
6475487 Fixing #423. Configurations now default to timing out after 30 seconds (tunable with configtimeout). This only happens for remote configurations, not local configs compiled using puppet.
a081d41 Fixing #418. The problem was that multiple objects might include Daemon, which means that Daemon#shutdown can be called multiple times.
c33d5e4 Using Time instead of Time.to_i for compile time, because some versions of ruby have trouble converting Bignum to yaml
6d791f5 adding client name to processing line
7670df2 Fixing #445. Nodes can now inherit from default.
afe77b6 changing selector error message
aab3214 reworking the selector case-insensitivity test
9f8a3b1 Removing an extraneous debug message, and fixing the case where the server compile fails in --test mode -- it resulted in an extra warning message.
ca1e36b Applying patch from #457, as submitted by Jeff McCune.
81ae09e making yum the default packager for centos
5735d48 Wrapping the resource generation methods in begin/rescue blocks so that failures cannot kill the transaction.
e8f3806 Fixing error-catching in resources.rb
a3041cd Updating changelog for 0.22, which fixes #429.
bda74bc Fixing #415. Configuration parsing now removes trailing whitespace.
f8115a7 Fixing #424. The configuration compile time is now cached in the yaml cache file.
53f3b8c Fixing rundir so that it does not throw an error when not running as root
c285d7a Fixing #437. Transactions now check whether graphs are cyclic, with a somewhat-useful error message if they are.
9720a97 Fixing #436. Also finally renamed pfile/uid.rb to match the state name.
db5494f Fixing #421 by changing the rundir to /var/puppet/run.
bfb5506 Fixing #416. There is now an option (downcasefacts) that determines whether facts are downcased by the client.
53c3f5a Make rpm operations much faster by suppressing unneeded verification
bcd81bc updating docs with new location for reference info
f069418 Moving the reference docs to the top level
c03a8c9 updates
42b78a0 Use a specific ActiveRecord subclass to check for the proper existence of AR in the Rails feature test, so that we don't kill everything if the machine has Rails installed, but it's an old version that doesn't support polymorphic associations
e64e64d Make the version string optional in the dpkg-query output parsing regex (Fixes: #425)
32bbb3a Clear existing yumrepo instances befoer listing - assumes list should only return "is" instances
3dea961 Enclose values in single, not double quotes; otherwise if values have $ in them, the manifest will be incorrect
5836c23 Allow listing of yumrepos
a676e08 Sync with latest in Fedora repo
965a82d Minor cleanup, leave cursor at beginning of indented line, not its end
c35b441 Add indentation written by Mario Martelli
f7d8350 Updating docs for 0.22.0
4ee6c97 Updated to version 0.22.0
98ed0ae Updated to version 0.22.0
38cfa67 Updated to version 0.22.0
3446dd6 Last round of fixes before the next release
954a285 Fixing puppet test task for older ruby versions
7afa69c Fixing rake test so it works with the new puppet loader
54c387f Adding #408.
d0ecc0e Messing around a bit with how tests work
2728f50 Adding a bit more comments to the :template function
704bd76 Fixing a few testing bugs that have crept in, and fixing a self-reference problem when configuring, graphing, and setting graphdir manually.
e756711 Fixing #411.
48bbd0b Further work on #407. I forgot to actually connect it to the interpreter internals.
f6beef5 Fixing #407. You can use external_node to specify a command to retrieve your node information.
f8f7c57 Don't rely on the type to store the actual NVR of the package; breaks in the provider tests since they call the provider slightly differntly
42c13e2 Adding a timeout to execs. This is not really a sufficient solution, since it needs to be added throughout the system, but this is a good start. The default timeout is 5 minutes.
6e10004 Using Puppet.settraps in puppet executable, instead of old ad-hoc code.
903b40b Applying patch by mccune from #409.
5e470b3 Regressing to always creating files/directories as root, rather than trying to do it as the right user.
bb72a08 Throwing warnings instead of exceptions when dpkg-query produces info we cannot understand
08a56cb Fixing module_puppet to use the usage? feature.
239727c Re-enabling the dirchmod test and fixing its syntax
2195b76 Trying to fix #364. Somewhat used the patch provided by nslm.
8fd9765 fixing filebuckets so that only the client bucket is created on clients
d5651f8 Fixing tests so they now include descriptions with all config options, which is now required.
a454dfb Creating two filebuckets by default, one for the client and one for the server
9c1a446 Fixing #403.
2b271f8 #398 is already fixed, but this will fix things so it cannot happen again
f4b2e13 Fixing #391. Keeping track of times of compile and freshness checks.
098081d Setting up specific allowed types for sshkey
5292e4e Handle continuation lines in inifiles properly; stick a little closer to how python's ConfigParser parses
2366c95 Explicitly require puppet/filetype; otherwise, tests for this module fail
cbd20f0 Simple script to produce type info
3b6bf05 Fix yum update breakage - query should not change the name the user gave us; instead, the fully versioned pacakge name is now stored in the instance parameter
587deea Tone down the debug spewage from yum
9115fef Adding extra connection statements and enabling concurrency support in rails, hopefully fixing #399.
0ef8971 Fixing #394. LoadedFile was not checking to see if files went missing.
f58bda2 The package name must match at the beginning of a line; otherwise we might get fooled by other yum spewage
caabe9b Not saving tags right away. This seems to cause postgres to explode.
9271142 Adding a check to the rakefile to throw a warning if the test task is missing
651640c Fixing #401. Transactions were trying to trigger every resource, even those that did not respond to the specified callback.
c140037 Not setting the graphdir to the puppet user, since it is only used by puppetd
127f0df Using text for parameter values, instead of string, so the fields support larger amounts of text
86e434e Adding postgres as a dbadapter option
2d25816 Fix trac #354, and some other oddities around installing multiple versions of the same package.
50965c7 Changing "sourcematch" to "sourceselect"
373f177 Adding sourcematch parameter to file.
cc05e8d Fixing the error thrown when a dependency cannot be retrieved, WRT to #395.
57d0933 Fixing #396. Using the provider command instead of a direct exec, which automatically captures stderr.
0887fcd Modifying the "Resource#set" method to simplifying adding new parameters
56619d5 A couple of small fixes to pass existing tests.
4482691 Fixing some failing tests on fedora.
3e933cc Enabling debugging except when running under rake.
3b2521b Fixing graphing tests, and correctly only using storeconfigs in tests where rails is available
54a838e Fixing #369. I was not flushing changes to disk when ensure was out of sync. This is going to become a common problem, and should probably be addressed by the framework rather than by individual types, but for now, it works.
b8f798f Fixing #390. You can now add --graph to produce dot files, and you can then produce pngs or whatever from those.
0a1dd1a Use Puppet::Util.sync instead of MonitorMixin to ensure that only one thread runs the executor at once
23b75e2 Fix a syntax error in lib/puppet/daemon.rb (That'll teach me to not run the test suite before committing)
38244fb Create rundir in a test that needs it
27c1b49 Switch puppet/daemon.rb to use Pidlock
16f7980 Switch the run-lock to use Pidlock instead of the ad-hoc code
e4843f1 Make Pidlock#lock return true if we currently hold the lock
e252505 Add a Puppet::Util::Pidlock class, for use by locks and PID files
c1035cc Add system library directories directly in puppettest.rb, so you don't have to do it by hand in every single underlying directory; also change the debug check slightly so that we actually put debug stuff only when we really want it
a333539 Applying patch by rainhead from #392.
7e62bb0 Add updated_at for all tables make sure it's removed from the resource hash that gets returned
6d8b3f3 Removing debugging
da3e9d4 Hopefully fixing tagging problem
280f0b4 Still trying to track down the tagging problem
79e9b46 adding a bit better error reporting when tags are bad
419cdf0 exiting sleeper after no more than two minutes
fa538bc Moving the tagging stuff to an "external" directory, instead of "lib".
0166004 Adding carriage returns to output of puppetrun
f52e2d0 Trying to clean up how rails is loaded
3a313ad Supporting arrays for the backup parameter
17306c0 Features now load dynamically using method_missing, so that undefined features never throw errors.
96f91f6 Adding a bit more testing to mounts, and pulling a bit of the transaction into a separate method to shorten the apply() method.
a2b0ee6 Finally writing unit tests for Transaction#trigger, and drastically simplifying the method in the process.
9ff80c0 *whew* Okay, simplified the splice method a bit, and I am actually somewhat confident that the stronger testing is correct. I have had a lot of problems with tests usually passing but sometimes failing, mostly because of ordering problems related to multiple edges.
bb9c813 Did a short-cut on the graphing, since we currently only support one type of subscription. This solution still will not scale to all that many edges, but it works, although it will fail if we need to support different types of subcriptions.
7ae62a5 A couple of small bug fixes
c4c3d77 Some tweaks to graph splicing, although I do not think it will be enough to handle some of the edge cases.
d07570b Looks like providers work again on Solaris.
6529822 I have not yet finished testing, but most of the providers now successfully pass arrays to execute() instead of strings, which means that the vast majority of execution problems are now gone. I will finish testing tomorrow, hopefully, and will also hopefully be able to verify that the execution-related bugs are fixed.
038d6a6 Fixing #387, hopefully.
a5cf056 Fixing #388. Paths now look a lot cleaner.
883c64a A couple of small bug-fixes
65e76e8 Fixing #353. It was as simple as exiting with a different error code depending on the results of the call.
d3a7c28 Fixing #386.
1d05739 Switching files to use a filebucket named "puppet" by default. Also, set up MasterClient to create that default filebucket.
92ff712 Fixing #365. I am not sure what the problem was in previous versions, because the new graphing stuff changed the solution to this problem, but it all works now.
8ff7e0c Closing #362. Case-insensitivity is handled by downcasing all host names.
f1dc103 Hopefully fixing #355. I could not actually reproduce the specific problem, but I found a couple of issues around the problem and they are all gone now.
a3ce917 Fixing #348. Overrides now support an extra end-comma.
5e58273 Loading the rails lib early on, so that the rails configuration parameters are accepted on the CLI, as noted in #357.
2742995 Fixing #343. Collections and definition evaluation both now happen on every iterative evaluation, with collections being evaluated first. This way collections can find resources that either are inside defined types or are the types themselves.
85b19c4 Fixing #349. Doing some hackery so defined types can now (again) be used as dependencies.
311aba9 Fixing #66. The "defined" function previously checked for definitions and types, but since types and classes can't have the same name anyway, the function now works for classes.
9bb5c50 Not downcasing facts any longer, closing #210 (although not using the patch from mpalmer, since I had not noticed the patch was there). Also, making all nodes, classes, and definitions case insensitive, closing #344. Finally, I added case insensitivity to the language in general, which should preserve backwards compatibility and probably makes the most sense in the long run anyway.
be711d3 Allow execution of bare strings as long as there's no attempt to change uid/gid
c616572 Fixing test to work with new style of graphing.
2c2177c *whew* Fixing the vast majority of the graph-related performance problems. I found a simple solution to handling events produced by generated resources, and that basically fixed all of the performance problems. Transaction tests still fail, but I wanted to get the fix in now so I do not forget it.
299bdc1 Fixing #380. The problem was that a method was sometimes returning :absent when I expected it to return nil when the group was not found. All fixed, yay.
e605c4a Adding some defaults to users, mostly for darwin because it is kinda stupid when it comes to this info
41562cc Adding test for the fix to #361
a9dd641 Fixing #361, I think. It appears to be a problem with missing a setting for realname.
1bdf379 Applying patch from #384, by jgonzalez
253376a Fixing #385. Puppetca correctly exits with non-zero exit code if there are no certs to sign.
36e8d65 Fixing #372 and #374. All is not perfect, since OS X still cannot set UID, but it is much better. There is still plenty of bug-fixing to do on other platforms, I expect.
115ec09 Re-add support for tags and file/lines
f851ca6 Adding :replace aliases, as requested in #366.
9f48706 All rails *and* language tests now pass, with the exception of a language/resource test that passes by itself but fails when run as part of the whole suite. Also, I added deletion where appropriate, so that unspecified resources, parameters, and facts are now deleted, as one would expect.
dc5f4dc Fixing most of the rails stuff. I think everything basically works now, and now I am just going through and making sure things get deleted when they are supposed (i.e., you remove a resource and it gets deleted from the host's config).
5a52855 Fix up a problem with initialising an sqlite3 data store, presumably only with older versions of Rails
3c93400 Adding daily snapshot tasks, altho they only work at my site
10dbb17 Some more graph optimizations; I think I am now close enough that I am basically just going to spend a bit more time making sure the modeling is right in the transactions, and then walk away for now.
b01ffe6 Adding a simpler and *much* faster tree_from_vertex method, and using it instead of the default one
a481f9b Requiring puppet/rails in the interpreter before Rails.init
9df9e4b Getting rid of the db init stdout and reindenting
02cfc44 Simplifying the splitpath method a bit, altho it is still strangely slow
9fa7794 Simplifying the the Puppet::Type[] method
0dbe96d Redoing the benchmarking a little bit
f622e18 Go back to restype and remove STI classes, they were more trouble than they were worth.
9ad62d2 Modifying rails test
0dac4ec Changing some of the error output. This gets rid of the duplicated information that occurred when definitions or nodes were duplicately defined, and it tightens the error output a bit.
0f78282 Adding unit test for #364. It passes on OS X.
dc96f98 Adding some selectability to host creation for testing. Using find_or_create_by results in lots of saves instead of one big one at the end, which causes initial saving to be much slower. To switch between them, just modify the value of "create" at the top of Host.store.
6b5d001 I like to checkin one-liners a lot. I'm cool. set the type when we create the object, might be a bit faster
7173c1f Don't use find_or_create_by_title since titles aren't unique.
e28c604 Remove old files, don't require pp anymore
3d070f7 These are the same versions from changeset 1837
0cd5799 Some rails modifications
6d9ae0c Don't dump out debugging stuff.
342a4a6 Don't symbolize the param names
56098ca Rename some stuff I missed when it was reverted
b5fd822 acts_as_taggable plugin
98ebb87 Moving the mount provider tests into a subdir, and fixing the basedir calculation in tests so it does not matter where the test is called from
8714e14 New rails stuff redux.
026ec4f Small changes to the test rakefile. This rakefile still is not completely satisfactory, as I cannot use it to load all libs but only run on test method, which is often important when trying to track down a bug that only occurs when multiple files are loaded.
8be0d33 Fix service.list, in particular for the redhat provider
29ded01 Fixing painfully difficult to find bug in defining exported resources
72f8b32 Reworking the package tests. Now providers are tested individually
f5e7915 Rewriting the test rakefile so test directories can be more than one directory deep. This will be particularly useful for providers.
40c0905 Fix up the filelist for gems, so that all of lib/puppet gets put into the gem, not just the top-level .rb files
c35988a Another round of bug fixing. Now everything passes except mounts, at least on OS X.
ab60452 Fixing the next round of bugs, mostly little things but I had to modify transactions so they are willing to delete implicit resources even if they have dependencies, else we would often not be able to purge files at all.
3937aa3 Never default to rpm provider; use up2date on RedHat. This also works on RHEL5, which does not have up2date, the provider properly fails over to using yum
c763346 You can now use the "resources" type to purge resources. I still need to modify transactions so they do not purge resources that have relationships. Also, apparently the noop metaparam was never actually working; now it is, and there is a test for it.
64d96e9 adding a note about facter to the faq
e96049f Change the filelist slightly so that the externally-included lib/rake doesn't end up in the gem
8829aa7 Adding a metatype to manage resources of a specified type. For now, this metatype just supports purging unmanaged resources. Also, fixed a few tests here and there
4abbdc1 Working some on the export/collect problem. It actually works now, but there are not yet sufficient tests for it, so I will leave the bug open until we have got the new work in place. I also added a "rails" feature, so I do not have to keep testing whether ActiveRecord is defined.
8fee538 Adding a short note on variable interpolation
8accd80 Adding a bit of clarity about file locations
dd1c4b9 Add a task to build Debian packages more-or-less 'directly' out of SVN.
01fecb1 Add external Rake task file as an svn:external, and modify the Rakefile to add lib to the load path
b3eb9f1 All tests should now pass, with the possible exception of some tests that might fail when all tests are run in one process.
e287d1e Almost all tests now pass. I have basically reached the point where I was before I integrated graphing, except that all of the relationship handling is now inside the transaction, and any kind of recursion (including file) is *tons* easier to model and manage.
37a059b Most tests now pass in the whole system, but there are still about 8 cases that do not work. I am working on those now.
374c830 Removing the explicit load for most types in type.rb
8aebdfc Removing the reference to the symlink type
2d43580 Most of the graph handling is now done, and all of the recursive types (basically just file, tidy, and component) now correctly use the generation mechanisms in the transactions, instead of sticking them in their @children array. Now I just need to go through the rest of the tests and make sure everything passes.
d3b76d6 Removing the symlink type finally.
cdd1e6e Another intermediate commit. Most of the graphing work itself is now done, but I am in the middle of converting files to use the graphs and at the same time am writing some actually decent tests for the file recursion stuff.
01e5b69 adding note about --no-client
8ff90ef Fix bug in example code: all resources now must have names
f3a0c48 Most of the graphing work is now done. I have also added the generator work in transactions, but I need to migrate files to using it. Until that migration is done, files will not work correctly for many cases.
a7354d0 Fixing link to fsconfig reference
ccd7b58 Intermediate commit -- I am ready to start pushing the graph stuff into the types and transactions, which will break everything for a little while.
c301b1b Make spec file work for Fedora < 5 and RHEL < 5
3e3f70e Adding GRATR and the beginnings of graph integration.
34c89b0 fixing typo
b3c3de2 Fixing #342. Classes needed to have their namespaces set to their fully qualified names, so that contained code and definitions looked for definitions starting with that fq name.
4076101 Fixing mount tests after fixing the backward compatibility
185ba8c Fixing backwards compatibility in mounts -- they were not correctly copying the path over to the name
5f5417a Fixing #347 (I hope). Doing a provisional require of rubygems.
c369e40 Fixing #346 -- on some scripts I accidentally used "feature" instead of "features"
c3c5851 Fixing configuration storage -- there was a check being done that caused false values to get converted to nil values, which failed in the database
25d563b updating syntax matcher to highlight dollar signs in prototypes
60af8e2 Updated to version 0.20.1
e313a26 Updated to version 0.20.1
68d9e78 Updated to version 0.20.1
7d46167 Updating changelog for 0.20.1
7fa96cb Another small fix, just for solaris
db5d9d4 Another testing fix
0efa969 Fixing more tests
5d2f954 Fixes to the test system, and a couple of small fixes to the main code. Also, disabled the "port" type, because I cannot seem to model it correctly.
f8b9e86 Fixing a small syntax error in the port provider
35de0e3 Temporarily reverting all of the recent rails work so that I can release 0.20.1
26b32b9 adding svn keyword to notify type and reindenting
e936fcc Removing the caveat so that the log message is always provided during a run.
b2e98b1 Fixing #339 for real this time -- fixing the log message
1bf97cd Fixing #339, and the bigger problem it concealed. Metaparams are now only added to resources that do not explicitly set them.
50d28ef Applying patch from #335
0a35c34 Removing some debugging, and trying to track down a bug where symlinks get recreated for now reason
ff06a8d Ported sshkey over, yay.
4e96031 Adding a NetInfo provider for hosts. Yay!
064ddbc Hosts now work again, and it should be straightforward to create a netinfo provider, too.
bb80c1b Ports are still broken, but I need to work on something else while I am thinking about how to fix them. Stupid /etc/services.
25b575f adding a comment to namespaceauth.conf
b2a49c9 adding up-to-date example configs
4d5f70f Trying to get a netinfo provider for mounts working, but i give up. I am leaving it in place but marked as highly experimental.
bd169b4 Mounts work again, at least with the parsedfile provider. I still need to create a netinfo provider, but it should be short and easy. And, painfully, I still need to port the other six or so subclasses to this new provider.
138150d Doing some refactoring in how state values are set. The primary motivation was to provide the ability for the "newvalue" method to specify whether the provider should still be called, and if so, in what order (e.g., before or after).
5685013 Fixing the state class so that blocks are optional for values. This is useful for cases where you want to specify values for validation but you want a method called on the provider instead.
0643113 An intermediate commit. All of the classes that use parsedfile are assuredly broken, since I have basically completely rewritten it. These classes have been a thorn in my side almost since I created them, yet they have been significantly less functional that I wanted. So, I decided to do the rewrite I have been putting off, just to spend all of the maintenance time now so I do not spend 3 days on them every release.
7c8614b Adding module for parsing files. This module is only included into the parsedfile provider base class, but it is cleaner to have it broken out like this.
f9d6213 Fix silly regexp mistake where lines with values containing '=' were parsed improperly.
b44ebe2 Fixing some warnings
9f8849e Mostly small changes toward 0.20.1
10634d6 Fixing #324. Mkusers was not specifically ignoring the root user, and it is now.
349e2aa Updating docs with correct links for the doc restructuring, as mentioned in #322.
5a4f807 Fixing #326 -- parseonly now just creates a simple Master without opening a port
cbb4578 fixing #327; debian packages now correctly register their "latest" status
87fd075 Adding a simple report that just duplicates client logs onto the server
10c860f Slightly more doc updates
114cd8a More doc updates -- I moved the doc headers into separate files, rather than having them in the code
b14982a Small fixes here and there. The rails changes needs to be pushed through the collection code, so I am committing so Blake can take a look at that.
aa2da58 Updating docs
f438bab Refactoring the doc generator a big
1f548f9 Updating documentation
87aea8b Fixing rrdgraph report (as marked in #334); also, expanding the docs on all of the existing reports.
51882d9 The new rails files.
cf166c2 Rails stuff part 1
28c283c Fixing some sticky problems with checksums when just using the "check" metaparam.
744ded3 Merging the code over from the oscar branch. I will now be doing all development in the trunk again, except for larger changes, which will still get their own branch. This is a merge of the changes from revision 1826 to revision 1834.
dc4d980 Syncing up with FE repo specfile (only mandatory changelog entries)
033de88 Making some documentation changes
e741b7b Fixing some Class.to_s handling
0930b5e Mostly rewrote intro doc
71924ad Updated to version 0.20.0
a488dd9 Updated to version 0.20.0
4688d93 Updated to version 0.20.0
f9f939e Updating changelog for 0.20
e3b4f23 Another round of bugfixing, including finding out that the tagmail report was leaving zombie processes lying around
07f616b A round of bug-fixing on OS X
ed38ba4 Doing some work on the DSL. It behaves a little more like the real language now, although overrides use the same syntax as normal resources, and there is no facility for specifying defaults
7b34e25 Another round of bug-fixes in preparation for 0.20.0
ead49c6 Applying patch from #318.
7261cbb Applying patch from #319.
3a6683e Changing the realize() function to be just syntactic sugar for a collection -- it literally creates a collector object now. The benefit of this is that it is late-binding, so file order does not affect whether a resource is available.
05080ff adding docs for virtual resources
a05b8f5 Adding a "realize" function that can be used to make one or more resource non-virtual. It is just syntactic sugar for a collection by title.
8a4bf1b Hacking cron so that it works even though I have changed ParsedType. The whole stupid thing needs to be rewritten from scratch, but this is the best i can do for 0.20.
d77d6d4 Adding prefetch of providers to transactions. Nothing is using it yet. I wrote it for cron jobs, but it is too much work to fix this for cron jobs right now.
f1ebef0 Fixing virtual object collection. I apparently broke it when I added rails collection back, and I never created any end-to-end tests.
52105c6 Fixing doc generation for objects w/out their own docs
1d35f28 Fixing a bug that only occurred if a defined resource was already defined in memory.
ada7777 sshkey now uses a provider
95f2fe7 Ported mount over to using providers
86dae84 Fixing ports to now use a provider
7e488b2 Working on migrating the parsedtypes to using providers for the parsing aspects. This just converts the hosts; I will convert the others next. This is all work from the sync-retrieve-refactor branch, modified to work with trunk.
ce4c494 Fixing puppetmodule to use env to find ruby
0472b24 First batch of fixes from running tests.
5ddbc36 Fixing sbindir path, thus fixing #302.
29ff4f3 Switching from calling "up" on the migration directly to using the "migrate" method. It is still not checking versions or allowing external forcing of migration, but it is a start.
b4ebe76 Rewriting nearly all of the tests for the tidy type, and redoing the internals of the testing.
9e5ea8c Fixing the test scripts so that the library path is modified in ruby instead of in the env line
72688e3 Fixing gennode; it was not actually adding the class code to the generated node.
816c5ce Adding a ruby header to all of the tests so that they can now be executed as normal ruby scripts. Using multiple commits because I am having some svn problems.
1d56ca6 Adding a ruby header to all of the tests so that they can now be executed as normal ruby scripts. Using multiple commits because I am having some svn problems.
624eddf Adding a ruby header to all of the tests so that they can now be executed as normal ruby scripts. Using multiple commits because I am having some svn problems.
67704e7 Adding a ruby header to all of the tests so that they can now be executed as normal ruby scripts. Using multiple commits because I am having some svn problems.
0859da9 Adding a ruby header to all of the tests so that they can now be executed as normal ruby scripts.
1020c04 Making all test suites executable, adding some tests for handling changing files from one type to another, and fixing #304. The problem with #304 was only occurring when backing up to a filebucket (I can only think the example code was wrong)
dad596e Fixing #291 -- the problem was that instead of throwing an error on a missing server, puppet was just exiting.
9a8636c Moving all of the configuration parameters out of puppet.rb into puppet/configuration.rb, and adding a PATH setting as requested in #307, although it does not include a default.
86b3386 Adding the ability to have hooks for configuration parameters. This will simplify things like setting the shell path.
32deb3f correcting warning about spaces before parens
c48f68c Adding patch from Jeff McCune, #317
9bd5593 adding explicit load of ast/branch to its subclasses
b9ed053 Format tweak for fact tutorial.
5403a91 Adding a summary of using facter and using imported facter facts with puppet.
90e4c7b Adding some documentation to the programmer's documentation introducing the concept of providers.
f545350 Adding some documentation to the programmer's documentation introducing the concept of providers.
7b75590 New documentation hierarchy: fixing indexes.
db24e17 New documentation hierarchy: fixing indexes.
628f6c9 New documentation hierarchy: fixing indexes.
9c01560 New documentation hierarchy: adding indexes.
ba33249 New documentation hierarchy.
da7cb9f New documentation hierarchy.
7b0e528 I was stupidly creating an error but not raising it.
29cce30 Moving methods around so they are alphabetical
ed89572 Committing the metatype branch -- this is just splitting the type.rb code into multiple files for readability
b4fd8d1 Catching missing ldap correctly in puppetrun
b5344f2 Fixing the problem reported by Adnet Ghislain where facts do not load on later runs.
8f9264b Fixing code from [1754] -- I stupidly did not even do a parse check, and I had to refactor the patch because parameters do not have code associated with their values.
94484df Applying patch from #234 from David Schmitt. This is also untested, and the patch is slightly modified.
4a8c5dc Adding modified patch from #256 -- apt now uses "responsefile" for the preseed file. This is untested, though, since I do not know how to test it.
a7c88e8 Adding patch from #308.
08900a4 Fixing #298 - refreshonly now correctly deals with specified false values
133c17f Fixing #305 -- logs now reopen when Puppet restarts, and there is also now an autoflush mechanism available so logs will flush to disk immediately. I also now trap USR2 and reopen logs when it is sent, so if you just want to reopen logs you do not have to restart the whole process.
c3cc162 Fixing #309 -- files now correctly replace any number of slashes with a single slash. Also, trailing slashes are removed, since that is how Puppet expects to find files internally.
c8ea361 Fixing #301 -- s/logfile/logdest/g
1c6cb60 Fixing #310 -- users no longer autorequire their homedirs, and files now autorequire their owner and group.
34f8337 Refactoring reporting. Reports are now modules instead of simple methods.
5b6ee8c Adding a "genmodule" equivalent to classgen, which we will use for reporting
1cdbe52 Added a section about testing.
96aabac adding id tag to tags.page
d532ea8 Documentation edit
addfe16 Adding a document to outline the use of tags
0716c83 Expanded documentation for rrdgraph report.
675495c Many, many, many performance improvements in the compiler (I hope). I did not change functionality anywhere, but I did some profiling and significantly reduced the runtime of many methods, and especially focused on some key methods that run many times.
ab0141a More specific configuration and argument documentation.
c7a7381 Documented signals the puppet daemons accept Documented host type to make it clear ipv6 is supported
aea6eaf adding id tag to reports
8f058a0 Fixing the rrdgraph report so that it creates a separate rrd directory for each host
b892093 Fixing weird case where the default node is in one node source and the real node is in a different one
06a7d34 Fixing ldap nodes -- they were always returning true because i was returning an empty array for missing nodes.
2489764 Changed document priority.
c1afdec Another minor formatting fix.
c9f6113 Missing tick.
d72c970 Adding some documentation on reports.
8a8191f updating install docs with new suse pkgs
1213d60 Removing some left-over debugging
28cee40 Merging the changes from the override-refactor branch. This is a significant rewrite of the parser, but it has little affect on the rest of the code tree.
e0e2913 Renaming logfacility to syslogfacility as recommended by lutter.
30fa686 Adding configurability to the syslog facility, using the "logfacility" parameter.
da0c862 Do restart as stop + start, since sending HUP to puppetmaster doesn't work (see trac #289)
ee76231 adding links to the real deb pkgs
dc6d426 Comment out the setting of PUPPET_LOG, so that puppetd uses its default
6e6cb8f Messages will now be at current loglevel, regardless of whether the object path is displayed.
30f9fa3 Added parameter 'withpath' to toggle printing of the object path.
8cc3c8a adding a note about single-quoting node names
5da80db - New type Notify for sending client-side log messages
f53b9b0 - New type Notify for sending client-side log messages
04c0c14 Changing warnonce to Puppet::Util::Warnings.warnonce.
8214c48 Fixing suidmanager so it uses warnonce instead of using a variable that only existed in Util
de304e5 Rephrased a short section about finalizing the object dependence hierarchy.
fee5116 Fixing reported problem of crons rewriting every time when the environment is set
244a11d Fixing what I hope are the last batch of problems caused by the addition of the suidmanager module. Also fixing a couple of other small issues that somehow cropped up. All tests should now pass again.
674841c Just fixed some RCS/CVS id tags.
98028ce Adding flush functionality as requested by Scott Seago
fd9b2f6 File types were dying silently on OS X when the group specified in the manifest was not a valid group.
db7d784 Fixing SUIDManager#asuser so that it only resets egid and euid if they were changed
dfef7e1 Adding a note about another error
d888d9e Added some documentation to the security page to offer some example invocations useful for generating/signing certificates for clients and servers.
ab225aa regenning configref with the fixed spacing
b4970a9 Expanded documentation of command-line arguments for the puppet executables. (Tweak)
cc08e2f Expanded documentation of command-line arguments for the puppet executables.
008a138 Expanded documentation of command-line arguments for the puppet executables.
f2ac4dc Updating changelog for 0.19.3, and merging the version changes over.
68016a9 ! rename file because rake_test_loader is dumb.
287b18c + New assertion: assert_uid_gid will check that the UID and GID have been changed to the proper values. This uses a fork and a FIFO to achieve it's checking. ! nonrootuser and nonrootgroup now only return users/groups that are less than 255, due to the "Darwin debacle" ! many, many, many fixes for suidmanager. This is rather embarassing.
55f2873 Merging the fix to server/master.rb
3aac2e1 Some small housekeeping things that I saw while doing other bug hunting
48082a1 adding note about the irc channel
515f3cc Harded-coded pathname to OSX's ssh_known_hosts as a work-around until the ssh pathnames are user-configurable.
7b5604b Adding some test reports
6f11dee + Puppet::SUIDManager - This replaces all calls to the built-in ruby 'Process' library for uid/gid/euid/egid operations, including (not surprisingly) Puppet::Util#asuser and a method to run commands and capture output. This is due to many inconsistencies (through bugfixes) between ruby versions in the 1.8.x branch. This is included in the core puppet library and can be used by all puppet types and providers. ! Modified Puppet::Util#uid to check (and warn) if passed a nil value. ! Changes to use Puppet::SUIDManager instead of Process and relevant Puppet::Util calls. ! Removed Puppet::Util#asuser.
320ac38 Updating CHANGELOG for 0.19.2
8f9dcb5 Updated to version 0.19.2
595d5ba Updated to version 0.19.2
6902f2d Updated to version 0.19.2
164c18f As requested by Christian Warden, triggering an object now results in an event, which can result in further triggers.
98004b2 Adding some error handling for when a non-existent report is asked for, and adding a bit more testing.
a1e27bc Adding trace information to autoload.rb
0bd3055 Switching Autoload#loadall from using "load" to using "require", so it will not reload already-loaded files. Also updating the checksum docs a bit.
eecc7cc Fixing error in tagmail when there are no messages to report
a468c15 Disabling a test on solaris, since apparently sh on solaris is different than everywhere else
64a3392 Small test fixes in preparation for 0.19.2
d35d04e Adding class list method to group. Also added a test to verify every type responds to "list", but it does not pass right now so it is disabled.
9afdf1f Adding an Autoload instance to Type.rb so that I can load all known types for documentation purposes. And, of course, loading all types in puppetdoc. Also updating zone.rb to fix markdown's stupidity in trying to interpret the ERB template, and adding some timeouts to puppettest.rb
1ae4344 more fixes to the zone examples
c8c3ee9 doc updates
2e17e4a Doc updates
9bd69c4 Typo: As stood had "remove" for "remote"
fcf16f7 Fixing #245, opened by marthag.
1ad76d1 Fixing #278, opened by Digant, with patch.
5faa45d Fixing #274. I just set :ensure to be :link when :target is set.
62abbd5 Fixing #283, opened by luke.
ea4b9c8 Fixing #285, opened by ericb.
c99843a Fixing #288.
2b27289 Fixing #293, I think. The problem was that the groups state was not correctly passing strings in all cases, which caused some very strange problems internally.
0870c5c Fixed a minor typo
dc8fb0a Fixing #292 (A bug in tagmail that causes any tag other than 'all' to fail) and #277 (tagmail report missing To: header).
afed9a1 adding an extra make target for debugging, rather than defaulting to always creating the debug file
e88bf77 Rake::TestTasks were running the test suite inadvertantly against the installed tree instead of the development tree due to a botched "libs" setting.
bc15e04 Fixing provider commands and Util#execute so they always include the command output when possible, as mentioned on the list
f0a9345 Regenerating docs, and correcting some markup mistakes
62917fc Small update to the fileserver tests; it was apparently not making some test dirs correctly
3891f48 Converting to using the Rakefile for testing. The old 'test' script is now deprecated, and I'll send an email to the dev list and update the docs to reflect that.
dcab464 Reworking test/lib structure a bit, and renaming all of the files so that their file names match their module names
abe1d3c Fix trac #282 (Change URL to configref, mention --genconfig)
7030aca Small modification so i can make more changes
6a1b43a updating changes from the trunk
6747b6a going through all of the other providers and making sure any reference to a state uses the :should value, not the :is value.
69d4083 Fixing case of silly states on os x, where files are owned by "nobody" and File.stat returns a huge number. I thought i had already fixed this, but apparently not. I added a test, and it is definitely fixed now.
8cbe19f Fixing the same bug in the netinfo provider -- it was retrieving the "is" value instead of the "should" value
6137812 Fixing #280; added a warning and exiting if no hosts are specified to clean
533a022 applying patch from #275. aptitude -q works fine on my testing release, but apparently stable does not support it
94f5865 Removing the no-longer-necessary type/nameservice info -- it is all in the provider tree now
94762e1 Trying to fix a bug where files other than site.pp do not get noticed for reparsing
176d483 Add config option 'node_name' to control what puppetmaster considers the proper name of a client (name in the SSL cert or name uploaded with facter) Default to name from the cert
fd4ef3c Better documentation around certificate revocation and mgmt
c8a6df0 Updated to version 0.19.1
ee8b8c7 Updated to version 0.19.1
6f85511 Updated to version 0.19.1
0e58f65 Updating changelog for 0.19.1
4a3c8d1 Adding testing for the default? method, and fixing it to support arrays and returning false when no defaults are specified
48992d7 Using the "trace" configuration parameter to determine whether a stack trace should be printed, rather than just using "debug". I added the param a little while ago and was using it internally in Puppet::DevError, but I just now went through the whole configuration and switched to using it.
cda7253 Adding patch from #235
5219205 Fixing docs, as mentioned in #271.
c04cb13 Reverting the work done in [1605] and [1606]. I have added it as a patch in #271.
08499b1 Adding the feature from #259. I had to rework the Scope#lookupvar a bit, but everything now works as expected when variables are either undefined or set to empty strings.
26bf373 Applying patch in #160.
e46d007 Fixing #262. I somehow lost the line that only added a given user's jobs to each tab.
0af8ad7 Removing a test in the parser that is no longer necessary because of how imports work now, and fixing a snippet not to interfere with a local fact
5669d1b This commit adds two important features (but which probably were not worth the priority I suddenly placed on them).
fbdd6c4 Specifically rescuing Exception, since apparently the default does not rescue LoadErrors and everything else
349bddd collecting output from blastlist, for later use
4cd37ad Merged test framework into trunk - still not ready until tests are converted to use it.
4897995 Fixing the "Adding aliases" message, so it is clear when an alias with spaces in it is used
6bb4814 Fixing #267. The problem was that the user provider was retrieving the @is value instead of the @should value, because it was using [] instead of the should method. I fixed the FakeModel to behave a bit more like real types, so that it keeps track of the is/should values, and also to keep track of which attributes are valid, since I immediately ran into another problem stemming from the use of the fakemodel.
e5aa761 Updating changelog for 0.19.0
2c57173 Raising element creation errors up outside the "create" method, so that tests can more easily tell when an object is invalid.
16d9d6f Fixing spelling of retrieve, to fix ##268
3b8c9ff Fixing #269. I was aliasing every case where the title and name were different, where I should only have been aliasing isomorphic types, which does not include exec
bf5d0bc Catching all errors encountered during loading, not just LoadError, to fix ongoing problems with rdoc/usage.
64eb1e8 Let puppetd listen (when given --listen) without a CRL
5e2091b Brute force fix for trac #266
37c9633 Fix test_host_specific to not depend on the path of the test directory and reenable it
aa56185 Expanding the Fedora/RHEL instructions some
47dc290 adding note about david's yum repo
8ff418c Fixing the problem with fileserver expansions, and doing a bit of refactoring to make things clearer
cf5291a Fixing the interpreter to nodesearch across all listed names, just like is done in the manifests. Also fixing a comment in type.rb
ca6ac62 fixing typo
0527426 adding gentoo notes
3e1b6bc Adding a :trace config option that prints stack traces of DevErrors, and using that in DevError instead of :debug
95269bf Adding test code for providers that makes sure the default and confine mechanisms work internally.
09f264a Add config parameter ca_ttl and deprecate ca_days; ca_ttl makes it possible to generate certs that are valid for < 1 day
130b245 Use Pupet.warning instead of nonexistant 'warning'
a5f4f53 Fixing #261. Applied patch, with small modifications.
0c0936b Adding a module for helping with warnings, starting only with the "warnonce" method
af1de89 Sync with FE repo
c651b19 Disable the sample fileserver module by default, otherwise users get spurious warnings about nonexisting directories
65bb635 Updated to version 0.19.0
61e42e7 Updated to version 0.19.0
12b219e Updated to version 0.19.0
e309b76 Modifying the provider base class so that it defines a method for every used command (e.g., you call "commands :rpm => 'rpm'", and it defines an "rpm" method. I then pushed this throughout the package providers, which are the heaviest users of commands.
c5ce953 Adding aptitude support, including a new util::package module that provides a method for package version sorting, and a couple of smaller bug fixes. This fixes #237.
2113eed Adding hasrestart parameter to services
fcc5bae Adding an "env" parameter to exec, for providing extra environment settings, as requested in #236.
8310c9d Adding a "withenv" execution util method, and using it in :exec for path handling. Next will be other env handling.
f8254c6 Fixing #230. If the first line in the cron tab, before the header, starts with TZ= then the header will be inserted after the TZ line.
fa16a92 Fixing small bug in cron where removed fields are not deleted from the file
e28250d Adding further gentoo support -- finalized portage support, plus conf and init info for puppetd
41c9081 Adding the Daemon module back into the Client class, which fixes #247.
46fbf95 Adding an "ignoretags" attribute to transaction, and setting it for downloading plugins or facts, and for creating config directories
b303e8d Adding the ability to download facts from the central server. This allows facts to be available before the configuration is compiled.
b36df18 A small fix to the install/update aspects of packaging.
47c86e5 Fixing the package type so that :ensure is always used for version specification, rather than :version, which is now deprecated. This provides much more consistency. I have not tested on all platforms yet, but I want to enable testing on Gentoo, also.
19992f7 updating documentation for how to specify versions
7eed92e Applying a patch from Jose Gonzalez Gomez; apparently this makes package updating work
40b2ed6 Adding portage support again, since it was added in the branch i reverted
617fe58 Removing all of the changes I made towards refactoring in the last couple of days. They have all been moved into the sync-retrieve-refactor branch. This branch will soon become 0.19.0, and will not include that refactoring.
8f39318 Committing a small amount of work in cron. I have decided that this is too last-minute, and not important enough to hold up the release. I want to get this refactoring done, but it is clearly not the 4 hour job I hoped it was. It will have to be in another release, I think.
b43b489 Committing functional mount support. All that's left in this chunk of work is cron.
639ed3d Adding first version of the portage provider, as contributed by Jose Gonzalez Gomez
655881c Ports now work with a provider
daa79e2 Intermediate commit; ports are not working yet
b657850 Fixing SSHKey support.
270f444 Beginning the process of moving parsedtypes to a provider. Each parsed type will have a parsedfile provider, which will be responsible for all of the file parsing and generation. This should allow us to create a useful DSL for file handling, but it also *drastically* simplifies these types.
b9b3384 This is the initial commit of the changes to sync and retrieve. The structure itself is now in place, and a few of the types (the most complicated ones -- file, user, group, plus exec since it was my easy first test) have been converted.
3733034 Renaming parsedfile to loadedfile, which makes much more sense and reduces some naming conflicts
a887993 Adding Gentoo support from #224.
c626796 Adding eat-last-line support in ERB
a115050 Adding pre- and post-hooks, as requested in #233.
f797487 Fixing #239 -- missing checks now throw an ArgumentError. This will break if any command purposefully returns 127, but that would be a bug anyway, I suppose.
ff18e55 Adding support for file purging, as requested in #250. Any unmanaged files in a purge-enabled directory will be removed.
18320ee Adding a "force" parameter in files to fix #242. Currently only used when replacing directories with links, but should probably be used in other places.
7fd5b6f Specifying true/false allowed values for file[:replace].
8cbe1d3 Adding logcheck script from #244.
2cb2e03 Applying patch from #251, and switching "confine" to "commands", so we can document the command requirements.
712e157 Adding SuSE files from #252.
42812f8 Applying the patch from #253 plus tests.
fd86428 Updating templating docs with more about usage, and adding installation notes about ruby segfaults on Debian
f587d88 Adding note about configprint, indicating what versions include it
989716e Adding zone patches
96350b2 Fixing #257, where host aliases were not being retained. The problem was that the "should" method was returning an empty array if it was not set, and it should instead return nil.
114debd batch of small bug fixes
2802b70 Making sure that the svn bin directory is at the beginning of PATH, rather that at the end, so the svn-versions of the exes are being tested.
b086280 Removing type/provider references on type removal
053f37c adding notes about the libruby deb package
77783e5 disabling reporting until i can find a way to make reporting only work with puppetd, not puppet -- clearly puppet should not try to report
199f5b0 Fixing the state so it tries to call provider methods and only checks for errors, rather than checking with respond_to?
b6b9d0b Setting both "report" to true by default; I am going to enable pluginsync by default once I have plugins well-documented
02b8b13 Fixing array printing in to_manifest
29edb14 Fixing service refreshing -- there was a problem persisting from the provider work
14d64dd downgrading the template interpolation message
fa0446b Adding back in the code to change the euid. I removed this yesterday because I thought it was redundant. It is absolutely clear that I need to add tests for running as separate users.
6f175ce Adding automatic stacktrace printing to deverror. I need to go through and remove the redundant puts in the rest of the code, but I need this now for some client debugging
a46a620 disabling chuser on os x, since it is broken with < ruby 1.8.5
a53d840 fixing provider commands; I broke them when making them easier to document
0f231b8 Skipping blank lines and comments in autosign.conf
9381d5f Fixing report lookup so it looks up by name, not method
948c96a Changing autosign mode to 644
762599b Fixing tagmail config processing so it fails when appropriate
0674c9a Fixing reports error reporting
a6c38b5 Fixing location of ca cert
04b2557 Fixing report autoloading; I was calling the wrong method, and they were never getting loaded
47dbf82 Upgrading Triggering line from info to notice
d45d22b Adding a module specifically for making doc generation easier, and adding defaults info to provider docs.
e1aff4c Last commit of puppet docs for the night
b9ad604 Modifying providers so that docs generate better
9b526ba Adding provider docs for required binaries
6aaeb05 Updating generated docs
5395e23 Adding pointer to templating docs into the file[content] documentation
8dbca3d adding notice that "$" is now required in definition prototypes
333c229 adding first draft of templating doc
628896b Adding a "configprint" option for printing out the local config state
9f7621b Adding a little more validation to the schedule, and documenting the source search-path stuff in files
ad32b71 Tracking down some weird bugs that managed to creep into the parser. I expect that the main ones were a result of the If support.
db0be8e Committing some changes to the %h expansion in fileserving. This change makes the expansion entirely isolated in the Mount class, which makes it much easier to test. Also, switched the fileserver config to use ParsedFile, which makes it a bit easier to understand and handle reparsing.
a44b1dd Committing the other half of the fix for #231; oops
ed15471 Fixing #231.
55d3fb8 Support for %h and %H replacement in the path of fileserver modules.
2540cdf Demoting the xmlrpc access logs to debug from info
38a184e Changing permissions on the cert file and the ca cert file, since it is no problem for them to be readable and sometimes it is required
b612a15 Try this; seems to work for machines with both ActiveSupport installed and not. MissingSourceFile is an AS thing, though it subclasses LoadError.
8fcec23 Adding up2date support, as submitted by Kostas Georgiou (with some modifications to support providers).
9576d1d Certificate revocation through puppetca. Keep a simple text inventory of all certificates ever issued.
4151fd5 Committing definition inheritance. I have not yet written tests yet, but my last commit pretty seriously broke some things without me realizing it, so I wanted to get this in.
1b2ee4b Adding "if/else" constructs. No operators, no elsif, but it is a good start, anyway.
ea32a38 Function autoloading now works as requested in #214.
bba972f Adding warnings and error throwing for #218 -- metaparams in prototypes are treated specially.
a1d71d9 adding faq item about ipv6 support
6e4d4c9 Accepting patch from #220, thus fixing the bug.
e322161 Fixing #225. Normal file copying worked with spaces, but recursive file copying did not. I modified one of the support methods so it works now.
bf43c76 Fixing #228. The real problem was that "present" should match any type of file existence, whereas it was just matching files. If the file was a directory, as in this case, Puppet considered it to be out of sync. Now, "present" matches files, links, or directories, but still creates an empty file if the path is missing.
aee1c6a adding cookbook into to the docs index page
7ade561 Support for certificate revocation and checking connections on the server against the CRL
c6fc6c5 Adding a link to the cookbook
b2031aa Making some of the metaprogramming a bit more explicit and a bit easier to manage. In the process, I have created multiple Util modules, only one of which is used for this current commit.
beba3e4 Finishing changes to support titles instead of two types of names. This is basically a bug-fix commit.
607d7c6 A first pass of changing one of the types of names to titles. I still have to fix a lot of tests, but the core itself is now working.
12452ee Merging r1468 from the implementations branch with r1438 from when the branch was first created.
4d6120a Committing changes that require dollar signs in prototypes
abaeb86 removing classing example, since it involves parameterized classes
e684cd3 Adding some documentation for the cfengine module
1eaf1bc Fix problem when --fqdn is used
e6aa4ab documentation updates, pointing to the suse yum repository and specifically mentioning package locations
0e862a3 Fix shebang lines in executables
450b495 Added comments to stay in sync with the spec file checked into Fedora Extras CVS
d6fc1b7 more ordering info
89b4dfd adding ordering information
7957ce0 fixing puppetdoc to add ordering info
f974ffc Fixing the master server so that it always uses the Facter hostname, not the cert or IP hostname.
eb8c687 updating links after a link validator
257fb78 fixing faq links
3ef4663 adding DSL class. Sorry, not much in the way of docs.
31b1d0b fixing more doc links
b2f1aa0 doc updates
b8bf113 Updated to version 0.18.4
94cc68b Updated to version 0.18.4
ce95ee3 Updated to version 0.18.4
f13c451 updating changelog for 0.18.4
cdeccab Another batch of bug fixes, this time focused on OS X patches. Looks like I did not test on os x last time.
b42eaee First round of bugfixes in preparation for 0.18.4
9e61510 Fixing #77. As I feared, this was a pretty complicated fix; I had to add a lot of infrastructure to both ParsedFile and Config. All config files now have a timer created for them, and by default they check for file changes every 15 seconds. If there is a change, they get rid of values set by the file (but not set on the cli) and set the new values, then the re-use all of the sections, so that any changed directories or whatever get recreated.
310b3a1 Adding timeout functionality to the ParsedFile class, in preparation to adding config reloading to the Config class.
c8537a5 Apparently objects were legal rvalues, which does not make any sense. Fixed this, and added a test verify.
21ae8fb Fixing #185. Added a check for cdrom sources, and added an override parameter.
039abd6 Fixing #176. You can now do duplicate UIDs (or GIDs on most platforms) with :allowdupe.
2091edd Fixing #200. I basically just moved the daemonize statement before most other code. This makes things a little less nice when starting puppetd manually, since it might still fail and the user would not know without checking logs, but it is the only real option at this point.
76aec7c Fixing #202. Just bumped the log level to notice and changed the wording slightly
3cc3f66 Applied patch in #203
7228413 Fixing #201; users now autorequire extra groups
ebd28e8 moving plugin evaluation into a begin/rescue block
8e25115 Fixing puppetdoc's output
041c07b adding all mailing lists to index
19e411b removing message about the statefile not existing
09e0792 more doc modifications
c9640a7 Updating some docs, and renaming configuration reference page
40e2db3 All docs moved over now, and the real index page exists again
813d1c9 committing docs before i move all of them into a separate subdirectory
f02f6f7 Adding Solaris SMF manifests and methods
0b90333 Fixing #191. I was only testing for parsed cron instances, not for created ones.
aba3d65 Fixing bug in scope/interpreter where nodes found in ldap must have parent nodes. The problem was that the the scope was using the presence of a parent node to determine whether a node was found. Instead I added a flag in the arguments to "Scope#evaluate" to mark nodes as found.
01c8808 Adding a unit test for plain "nodesearch"
08650c1 fixing html markup
e74b8af fixing html markup
8273f21 fixing index page in the docs
b23b797 Updated to version 0.18.3
fe8ce26 Updated to version 0.18.3
a984a90 Updated to version 0.18.3
8063ab1 Fixing filebucket server so that paths are not added multiple times
1ab4594 Adding tests for previous config bugfixes, and updating changelog
a6cc3e4 Fixing reports so that multiple host report directories can be created. There was a config conflict before.
73556a8 Fixing templating so it immediately fails when a variable is not found, as opposed to passing up the method_missing heirarchy, which was causing a nasty memory leak and some kind of weird, long-running search
1ec1b99 Fixing weird case involving interpolating config params in a URL
8f28c6f Fixing weird cases where configs might think non-files could be files
b116ac7 adding sysidcfg param to zones
a3849d7 Fixing templating bug that can result in what looks like an infinite loop, and changing default timeout to 2 minutes instead of 30 seconds
86a92de Reducing log level of missing file
7139901 Fixing error when template does not exist
3fbd06a Fixing misstated error name ExecutionError in blastwave packaging support
829c754 Fixing reports server so it refers to the main server
0acebb1 Default the passno to 2, defaulting to 0 is a bad idea since it disables fsck
44c54fc changing plugin owner to root
9be1e0b changing default plugin host to be $server
a4a04fe adding rake targets
0c96fc6 Doc change: explain what the values for ensure do
67dab0e adding another state that is equivalent to "stopped" for smf services
8a10b08 Adding the newly generated docs
e57f6e7 More documentation updates. I think this is sufficient for replacement of the plone site.
9b7f428 Fixing rakefile so it generates docs from markdown, and adding big-picture.page to the menu
70877fb removing faq.rst file
fefe1c5 Updates; remove mention of patches from specfile completely
f42666c updating changelog for 0.18.2
eff8d6e Accepting the patch from #190.
6b281ed removing cf2puppet from rpm
bd9fd8d Updated to version 0.18.2
71036e7 Updated to version 0.18.2
aa87963 Updated to version 0.18.2
afe84ec small fixes towards 0.18.2
e17f4ed adding host information to reports and tagmail report
1503b42 renaming tagmail config file
c3a8d45 Redoing reporting a bit, so that reports are now defined as methods. If they are not methods, then they cannot use return, which makes things a bit uglier.
3c22bc9 fixing some smallish bugs in preparation for 0.18.2
73569d0 fixing a small but important typo, and adding sunfreeware as a dupe of blastwave packages
87ce8ed Adding blastwave packaging, and doing some fixes on gem and sun packaging
2e78526 Some updates resulting from trying to track down a segfault introduced when I upgraded to 1.8.4-5 in Debian. I never found the segfault and had ot downgrade to 1.8.4-1. I expect it will not be encountered in real life, only in testing.
e57c513 Adding Ruby Gem support to packaging
25cf31b Adding minimal update checking for templates. It will only check the templates that have been parsed in this process, but it is better than nothing.
c899e23 documentation updates
c1e0bc6 More report and metrics manipulations. This should be the last of it.
34e779f Significantly redoing metrics. There are now no class variables for metrics, nor no class methods for it.
24f07e0 committing tests for previous changes
dea7e24 oops; adding transaction report class
70143d2 Trying to merge metrics and reports. There is now a separate transaction report class, and it works throughout the previously existing system. I will next go through trying to make a metric report that graphs the metrics in rrd.
795ec70 adding a "thinmark" method, which does a simple benchmark with no logging
19b5d30 Accepting patch #189, although I am just putting the environment statement in the main part of the class, since there are two apt commands
ff6562f Fixing #133. Added a "notify" and a "before" metaparam; notify is the opposite of subscribe, and before is the opposite of require.
9bb9e10 Fix a small bug in mount where parsing fails if dump and pass are missing (they are optional on Linux) Revamp the tests slightly so that they parse fstabs provided in svn rather than relying on the fstab on the system the test is running on.
f792a02 Moving the template handling into a simple wrapper object so templates don't have full access to the scope object without some real hacking.
8b60619 adding some tests for the template function
a6dc7f2 Adding initial template support. It is just a function, and a method_missing method on Scope.
e47a987 First commit of complete reporting support. The only existing report at this point is the tagmail report. I expect reporting to get significantly modified from here, but it is a good start.
ea91896 changing the #!ruby lines to #!env ruby
1677594 Adding reporting client, server, and tests. At this point, the server just stores the report in a file as YAML.
56a2845 Adding report collection to both statechange and transaction.
d275489 Updated to version 0.18.1
35ef37b Updated to version 0.18.1
427831c Updated to version 0.18.1
7adafc6 For each type, adding a "new<type>" method to Puppet::Type, so instead of typing Puppet::Type.type(:file).create(...) you can now type Puppet::Type.newfile(...).
e8c57ae Cleaning up plugin handling a bit -- they can now be colon-separated paths, and I added a separate "plugindest" setting for determining where plugins are synchronized to. The major feature I added, though, is that Puppet::Type now knows how to load plugins, and treats :pluginpath as a search path for plugins.
d98ab11 Fixing zone tests
4985d8f adding message about retrieving plugins
dec4053 updating CHANGELOG for 0.18.1
5471211 Moving the timer monitoring to after the services are created (because they actually create the timers), and adding a sleep statement to give the threads enough time to create the timers.
ad1396d Fixing backgrounding in puppetrun; I had the bit flipped between the client and the server, such that setting --foreground caused the clients to go into the background.
5be3c10 Converting Parameter#proxymethods from using eval to using define_method
b2304f1 Making sure fail function converts everything to strings
c363af0 Adding "fail" function, which will raise a ParseError if it is encountered.
57a5a71 Catching errors thrown during object evaluation and marking the objects as failed.
506269f adding hooks for ignoring files in the plugins directory, and defaulting to ignoring cvs and svn files
7685957 removing that info message, duh; it produces a lot of spurious output during parsing
c886194 Adding info messages about errors loading plugins
772ea91 Adding support for special freebsd @schedule crap. Also making sure that cron listing works as expected.
08f113c switching puts to print, so the carriage returns are always included in the messages
bdd1761 Largely refactored how log destinations are handled, although it is not exposed externally. Most of this work is related to handling a large number of small problems related to threading.
73a4bcc Changes to make puppet package more LSB compliant. Update specfile for very latest Fedora ruby packaging guidelines. lsb-config.patch only checked in for documentation purposes, since changes are part of this checkin.
0411f74 Fixing some more small problems in puppetrun
31c17e4 Adding more docs to puppetrun, and fixing bug that can cause hosts to get skipped
faab17b adding - to HUP in init scripts
bb5366f Updating init scripts to use HUP for restarting
3c5b10d Adding a "latest" test for rpms, since I have been told this is not working. It seems to be working fine, but the test cannot hurt.
5cf2a4d Adding HUP and USR1 hooks
4a71706 Fixing #178. I just added URI escaping and unescaping to file names.
f9a4d7a Fixing #175. The setpidfile setting was being ignored.
d812840 Fixing #182. Added a retry section to try reconnecting to ldap. Only one reconnect is attempted in a given search, and LDAP produces bad enough error messages that we reconnect regardless of the error thrown.
46824cd Setting pluginsync default to false, and (hopefully) fixing autosign problem when the file exists and autosign is set to true (#180). The problem was that the puppetmasterd script was redundantly setting autosign in the CA, when the CA already knows how to deal with autosigning, which meant that autosign was being set before the config was parsed. Thus, there was no bug when autosign was set on the command line but there was when it was set in the config.
15905bd Fixing broken symlink behaviour mentioned on the list
0a1e847 Adding plugins and plugin management. The Master Client will now automatically download plugins if pluginsync is enabled, and they will be automatically sourced.
edabf9e documentation updates
4df2583 More documentation changes.
8ad2008 adding id tags to all of the docs
58826ca further work on converting from rst to markdown
b6a52b7 further work on converting from rst to markdown
3772aaf further work on converting from rst to markdown
e891ffb updating some docs and puppetdoc in preparation for a move to webgen instead of plone
90e8ad8 removing the old rst index file
644fd4e updating docs to work with webgen
f090760 Fixing my autorequire fix; oops
084a31d fixing autorequire message to include the object type
bdb9110b Delete entries from the config file if their should is 'absent'
883921c Test that setting a state to 'absent' really deletes it from the config
e841d8f Adding test and fix for empty execs being ignored
6ef3d88 fixing interpreter to initialize ldap in the nodesearch_ldap method, which really only matters for testing (since it is already being inited in the nodesearch method
662fcaf making links even if the target does not exist
0ab461b Updated to version 0.18.0
daac8cf Updated to version 0.18.0
8779dbe Updated to version 0.18.0
ae3dba9 updating changelog for 0.18.0
ead6b17 updating documentation for sshkey
20b0a6d fixing transaction tests to just warn when the user is not in more than one group, rather than failing.
be92c44 Setting options and the facility for syslog
9a1b9ec Fixing some logging issues with puppetmasterd when daemonized with verbose mode on, and fixing ldap support when daemonizing
c1dd0a1 Changing statechange noop message so it's a bit clearer
603a53c Just logging host failures, not exiting
c1f0fb7 Adding fqdn, an --all flag, and --test mode to puppetrun
f86357d adding namespaceauth and --listen docs to puppetrun
97c7342 Adding fixes for solaris zones
02d397c abstracting out ldap connections so that there is a single method responsible for all of them and a single connection can be shared in all classes if necessary
076e888 adding ssl usage to puppetrun
15da00c Fixing ldap usage when ldap libs are not available
4a5b886 removing extraneous debugging
7ed5560 Fixing installer; it somehow got broken with recent DESTDIR fixes
fd8e080 Fixing #173. At this point, I am just calling both "--add" and "on", or "--del" and "off". This should probably be broken up into other states, but....
ef163ba fixing parallelization to match the docs
1dfd554 Fixing packaging to deal with the fact that yum exits with 0 exit code even when it is told to install a non-existent package.
df340d6 Correcting puppetrun docs and fixing a test so it works with older versions of facter
b4b3c27 Adding support for default nodes as requested in #136.
ba4071c changing puppetclient schema to descend from top instead of iphost
07e0d59 Fixing #169. Tags are ignored during config.
c380bfe Fixing the main bug reported on the list today relating to file sourcing truncating linked-to files.
90762c5 adding noop marker as requested
ec0609d A round of bug-fixing in preparation for the next release.
9af5d69 adding nothing test to zone tests
a6122e8 Fixing ldap node lookup. The test was set up badly, in that it did not actually provide a way to enable ldap node support, even though there was a config option that should have worked. All works now.
360a405 turning on output flushing
edfaf6e Adding support for following referrals
555e1b8 Fixing #135. I was setting the object to the result of an include? test, instead of just "obj = ary[val]", so all but the first bucket-backed files were getting errors.
8ceb1f3 Found a bug where single-value selectors can fail on a second compile. Fixed it, and am now compiling all snippets twice.
4ca7ece modifying rakefile to specify the package hosts; they were previously hard-coded in the build library
09d2cd0 Fixing #168. Reworked the regex to allow matching TLDs.
1fc4ec3 Fixing #167. Started with the submitted patch and made a few more modifications, and added a regression test.
c90d0b1 Fixing #157. Objects are no longer allowed to be their own parents, and there are checks in both directions to stop this.
7c358df Fixing #166. Function names are no longer reserved words.
e73f2d4 Fixing #158. I did not add a force option, since I always back files up before I replace them.
4266f64 adding faq to docs
d6d05d4 Fixing #154. Basically just accepted the patch that fixes master.rb and added a test case for it.
1cef8f5 Applied patch from #153.
2257d6f Fixing #155. It is now valid to have arrays with no values, although you will still likely get erratic behaviour elsewhere in the system, depending on what you do with this.
0e52409 Fixing #159 -- packages now have a default value for ensure (:installed).
3758bdb adding rakefile for the docs
1a93e6d copying all documentation from the plone site
d84827e Committing largely complete Solaris zone support. I still need to add static filesystem support, but everything else should work.
73c5c58 removing one of the stack traces from error output
95f273e Fixing #163. Strings can now correctly escape dollar signs.
a3ed629 Intermediate commit; most of the core zone functions now work, and some of the configuration functions work.
81ce66a Fixing node tests to handle comma separation
011e811 temporary commit so i can transfer my testing to a faster, sparc box
add6b80 Fixing #160. Fixing the error in Puppet::Type#[]= and scope.newobject
76ff83d Fixing #161. Basically, AST::ObjectDef now catches when users specify a name as a parameter instead of the name before the colon and modify the results accordingly. This catches this kind of problem, and the normal name handling picks up everything else.
b08816b Fixing #162. Node names must now be comma-separated.
2fcbc7f Adding an "execute" method to Puppet::Util, and including the module in element.rb
354b945 adding zone management stub; switching to my home vm for testing
98ad43a fixing destdir in installer, and adding solaris conf stuff
4cd3019 Did some work on making sure object removal actually works, thus stopping some potential memory leaks. Also explicitly removed objects in more places, again hopefully forestalling memory leaks.
45a9edb Reworking cron; adding many unit tests, and making it much more like a ParsedType (although still not quite the same). Too many of my tests were invalid; I think those are all fixed now, and it appears to work as desired.
3ab4a89 Small fix to include puppetrun in /usr/bin
62a0ff0 adding puppetrun to the red hat spec file
fda013a Updated to version 0.17.2
3c15a28 updating changelog for 0.17.2
a08ca93 Fixing #138, all of it, I think. Environment settings are now allowed, although all bets are off in terms of parsing existing environment settings in crontabs.
69cf2fe Adding a small fix to cron tabs; they will at least parse tabs that have env settings in them, although you still cannot, at this point, set them.
0381cc1 slight ldap fixes in puppetrun
d55adda First version of puppetrun. It seems to mostly work, but I need to test it with greater parallelization.
5671ce8 Added the last of the tests for the runner, along with the necessary work in puppetd to be able to start it.
b3ea53c Adding a lot of structure to puppet.rb to make it easier to manage multiple objects in a single process, including making it easy to add threads. Added some testing for all of that.
93771b7 fixing user[:groups] management when the user is absent
738698c Updated to version 0.17.1
ed9adf5 updating changelog for 0.17.1 and 0.17.0
9b5de11 Allowing empty files
5382118 Fixing #146. I think I mostly just fixed the error message; I do not think there was another bug there.
89ce72f fixing stupid debian rails mistake
dc3a6d5 Making sure file recursion works for all valid inputs
373afa3 updating version on spec file
4296b02 Updated to version 0.17.0
3be0f95 Wrapping the host storage into a transaction. It might have a slight performance improvement, but, ah, unlikely.
9d6166e adding a test to make sure that defaults get taken up by components
a0bcf5a Adding code to try for the rails gem if the library cannot be found normally, and adding some protections in case there are problems
122e2bc only performing collection tests if activerecord is available
8f14c3f failing more intelligently in init if ActiveRecord is missing
def5175 Making sure yum fails on unknown packages
2e9f1c4 removing extraneous logging
d9fdd8e I believe I have finalized export/collection support. I still want to go through all of the code and s/collectable/exported/g (thanks to womble for that term).
ba57dff I had to redo how the scopes handled collectable objects (which I will soon change to being called "exported objects"). All seems to work now, though.
22e70f0 Made a *huge* performance difference in storing hosts -- down from about 25 seconds per host to about 5 seconds on my machine. I will almost definitely still use forking or something to make this not affect the clients
637cc71 I appear to have object collection working, incredibly. This commit does the collection from the database up to adding the objects to the current scope, which is what sends it to the client.
9e9ef1a The "collectable" syntax now works end-to-end -- the parser correctly recognizes it, the AST objects retain the settings, the scopes do the right conversion, the interpreter stores them all in the database, and then it strips the collectable objects out before sending the object list to the client
8ed666a adding a few more fields to the host table
5863a03 Adding initial rails support. One can now store host configurations using ActiveRecord into a database (I have only tested sqlite3). Tomorrow will be the grammars used to retrieve those records for object collection.
0819e35 Adding some small changes towards fixing #140 and #83, but this work needs to take a back seat to object collection, so i will come back to it later.
678e142 Fixing #141. It was a problem related to the recent parser changes I made.
578cf7e removing some extraneous logging
a2a4dd5 Updating doc system to add the list of valid values to the doc string, and tweaking a few docs.
710bf0d Slight modifications to package parsing on *bsd. It should be better about catching the version number, and unparseable lines are now just warnings, not errors.
9e77e7a It is just a snippet test, and thus a functional test but not a coverage test, but definition overrides officially work. This was important because it enables definitions to be collectable, which was not possible without the mechanism that enables this.
513b87a Preliminary commit of the first phase of the parser redesign. The biggest difference is that overrides should now work for definitions (although i do not yet have a test case -- i will add one on the next commit). The way this is implemented is by having scopes translate themselves at eval time, but in two phases -- the first phase does the overrides, and the second phase does the evaluation of definitions and classes.
fe16f83 making a test to verify that the functionality womble is looking for now works
bb60cab Making trigger logs much clearer -- you now get info logs indicating how many dependencies changed, and debug logs indicating what those dependencies are
88c3f7c Changing how events work. Events are now responded to inline, while an object is being applied.
7b7ac18 Changing default for pattern to include the binary if it is included
f0aeaec require the very latest facter to avoid problems because facter changed iphostnumber to ipaddress
e06c661 Small bug fixes
58cfd1e Fixing the problem that lutter ran into; the issue seems to be that Facter could not find the ipaddress on the server.
18de804 fixing log messages
a7fadbe fixing log messages
43fdd89 Updated to version 0.16.5
64a58e4 updating changelog for 0.16.5
44f1579 Fixing a stupid bug i managed to introduce in 0.16.2 (probably) involving importing files with classes in them. This is a better solution than what I had before the bug, anyway. Also, some documentation fixes.
a9df49d Fixing some naming problems with crons, and adding appropriate tests
e8c912d Allowing dashes in class names, although grammar rules restrict it from working anywhere except node names or in tag(). They are valid in host names, and many companies have them in the host names; in fact, this fix is for a company with this exact problem -- they cannot use puppet with their nodes because all their hosts have dashes in the host names.
37d2850 Switching to just using "preserve" for file copying in file#handlebackups
8b0481c Updated to version 0.16.4
4b84ca9 updating changelog for 0.16.4
b67a19b Fixing #132, which involved creating a separate CA client and using it to retrieve the certificates. There was more work to do because of the weird client/daemon/server heirarchy.
a435d07 Updated to version 0.16.3
3f08155 updating changelog
2faa447 Bug fixes from OS X for 0.16.3
5e246ab Hopefully final bug fixes in preparation for 0.16.3
cc5ce34 Fixing tests looking for pmap
a1574a5 Fixing TransObject#to_type so that it does not modify the object being converted
7825f49 Changing test for service paths; only testing if it is a directory if it is present.
65f6656 Added some code that could be used later to make sure the user and mode are also copied on backups.
0ad65e9 Adding a check to make sure the mode is copied over.
84db91e Fixing the docs a bit for the executables, adding a --daemonize option to puppetd and puppetmasterd so they can still be daemonized with debugging or verbosity enabled, and causing puppetd to fail to start if a PID file exists (and not setting a pid file if running with --onetime enabled).
12c122c Puppetd now has an option for listening -- just run the --listen option, and it will start up with a pelement server. It will fail to start if the authconfig file (defaulting to /etc/puppet/namespaceauth.conf) is missing, since it defaults to access at this point.
047e63f Making file copying significantly faster -- i found an extra call to "describe" in file sources and an extra read/checksumming of the dest file
94caa8a Fixing #128. md5lite was being used instead of full md5. At this point, md5lite cannot be used for source copies.
bcfc469 Adding in all of the patches necessary to make a prototype rails interface to puppet nodes work. The biggest change is that there is now a separate NetworkClient class for every Client subclass, because otherwise you get namespace collisions. Most everything other change is a relatively minor patch.
9539dbb Adding in all of the patches necessary to make a prototype rails interface to puppet nodes work. The biggest change is that there is now a separate NetworkClient class for every Client subclass, because otherwise you get namespace collisions. Most everything other change is a relatively minor patch.
9b627cd Trying to track down the bugs reported this morning, so I added some more test cases. I did find a bug in the filebuckets, fixed it, and added a test case.
003e897 updating changelog for 0.16.1 and 0.16.2
a78bf1e adding "clean" mode to puppetca
bda8e52 This should have been in 0.16.1. Moving the "setclass" statements around so that classes are set before a given class's code is evaluated, so it can be tested within the code, within node defs, components, or classes.
bff9463 Adding sum type to the retrieved sum if it is not already there. This provides backwards compatibility for existing cache files.
feff317 removing unnecessary debugging
baa412c Adding "defined" functino to puppet, so you can now test whether a given class or definition is defined.
46ce36b Creating a simplistic, generic function framework in the parser, so it is now very easy to add new functions. There is a pretty crappy, hardwired distinction between functions that return values and those that do not, but I do not see a good way around it right now. Functions are also currently responsible for handling their own arity, although I have plans for fixing that.
ccc4d95 Modifying non-existent-package test to make sure syncing fails, and modified ports package type to check the error output instead of the return code, because the portinstall command returns 0 even on failure.
e64bd22 Fix ownership on server files (trac #122) Change ownership on /var/puppet
9fe0b37 removing patch from red hat spec file
a0b4553 Final commit before 0.16.0
63cdc6c making corrections to pass tests on freebsd
d9fd002 Go some work started on developing authorization, but I have made little progress. I might wait on this for the next point release.
4a029d9 pelement listing now works
d91b7df Added a list class method to just about all types, and it seems to actually work for everyone. Now just to add a list method to the pelement server.
a9b67cc Adding a "list" class method to most types, and using it in the tests for the pelement server to verify that objects can be copied using it. I expect that most package types other than apt/dpkg are not yet working with these tests.
e24a299 A simple first version of an object (called "pelement") server is now in place. There is not yet a client, and the tests are pretty simple so far -- only files have been tested yet. I had to make a significant number of modifications to the file object in order to get this all to work, and one of the big changes I made is to the internals of the checksum state.
ac04981 Actually adding the ports file that provides freebsd port support
3f9e918 Adding freebsd ports support
c83bc91 fixing test to know that i skipped alerts
538bc0c Fixing service stopping; I had the %x{} command quoted
6f66011 Fixin #102. The syslog name is now either the name if the process (if that name includes "puppet" in it) or "puppet-" and the name of the process. Also removing the "alert" test messages, since they result in a wall.
d2634ba Fixing #118; the hash is now always 8 hex characters, 0-padded. Also changed the CA cert name to the FQDN of the host serving the CA, rather than "CAcert".
449f662 Fix handling of run files so services can't be started twice (reported with patch by soul916 at gmail.com)
21584a9 Don't create empty log files in %post (based on report by soul916 at gmail.com)
a564e49 Changing the log level of the "defaulting to base service type" message
d56870c Fixing a bunch of small bugs, mostly found by testing on solaris, and added a check to the test system that points out memory growth
0478f78 changing set to tag in the tests
26f18a2 Fixing puppetca so it does not call chuser; instead, it is configured to create all of the files with the correct permissions and ownership (using Config#write and Config#writesub).
c3961ae Adding doc generation for exe arguments
133ad87 Oops, typo in client/master.rb
689dbf4 Adding --test option to puppetd (it enables --onetime, --no-usecacheonfailure, and --verbose), and modifying the docs a bit.
cd9ea80 Adding locking to the master client, so that only one copy of puppetd will be running. This should make it safe to run puppetd manually while it is also running normally.
71793fb Changing "set" to "tag"
f522a7e Adding the host name as a tag (stripped of the domain name)
373fb3b Modifying "setclass" on scope to check the validity of class names, now that "set" can be used to set them manually, and added a test for it.
8df349c Fixing the language side of #109. Added a "set" keyword.
de0d1dd Adding a few informative facts on the server side: serverversion, servername, serverip. And only printing the parse time in the interpreter if it is not a local connection.
bca4f5e Adding the puppet client version to the fact list as "clientversion"
9f92a3d Adding the puppet client version to the fact list as "clientversion"
4d75041 Adding a "tag" metaparam
201aa02 Adding simple benchmarking, and using it in a few of the more obvious places. Also, fixed a bug in Scope#gennode.
0507486 Fixing #117. If only one value was provided, then it was not placed in an array, yet AST::Selector expected an array. The grammar needs to have some abstraction added or something, because I seem to have encountered this bug for every ast type that supports arrays internally.
ae4b12e Revamp the yumrepo type to deal with repositories defined anywhere in yum's config files. Adds a generic module Puppet::IniConfig for parsing ini-style files
8df6e84 another small mount fix; this time, for stupid os x
88dd992 committing version changes
d10a638 Committing an important fix to mounts; since i am sure no one has downloaded 0.15.3, i am just going to rerelease 0.15.3 with this fix in it
83d5236 updating changelog for 0.15.3; I need these exec fixes for my client
e5be7d3 Adding autoloading for types and service types, also.
fcce820 Okay, last one, hopefully. Modifying checks to support arrays.
37a4a55 And, one more time. My test for the last bug did not actually retrieve, so it did not enounter the problem, and i had also forgotten to add the "check" boolean to the checks. Hopefully this will be the end of exec bugs for the day.
4ab74ce Fixing checks so that they can run even if the set cwd does not exist
50ffa7f adding a bit of debugging
1e4abae moving cwd existence check into "sync" instead of "validate"
7dae24f Fixing a small bug in type.rb that ignored false values (instead of nil values), another small bug in value setting that resulted in the file and line appearing twice in errors, and added validation to all of the checks in :exec (along with testing for all of it).
b0edb35 removing patch from spec file
122cf58 updating changelog in preparation for 0.15.2
013cfd2 Adding darwinport type.
9697354 differentiating openbsd from freebsd, adding freebsd, and autoloading package types instead of manually loading them
f540ec8 fixing a couple small bugs in doc generation
668342e fixing Config#mkdir test to not check gid on any BSD, since they appear to ignore egid when making directories or files
572648e adding deprecation notice
84693d6 adding some docs
2b27545 renaming; i hate bsd
ee65279 Fixing #103. There are now no such things as node scopes; the entire tree is evaluated on every node connection, and node facts are set at the top-level scope. This includes,um, the code; the last commit was accidentally just test changes.
c3c413e Fixing #103. There are now no such things as node scopes; the entire tree is evaluated on every node connection, and node facts are set at the top-level scope.
a0728c0 removing the parser dir
8db837a getting rid of the parser tree, and moving everything into the language dir
d4a5b48 loading yumrepo in the test, since it is not being loaded in the main code
e8c0471 Fixing a couple of bugs in preparation for 0.15.2; mostly they were in the testing system and resulted from changing :File to :Manifest in server/master
9230289 Disable yumrepo type since it won't work with the FC5 repo files
b5c759b Fixing #108
d8b4b0d adding -e ability to puppet executable
c0a9e5f Change how names for nodes are specified: the 'node' keyword can be followed by a NAME or by single quoted text, i.e. fully qualified names for nodes must be enclosed in single quotes
5d42cd5 Fixing the class file to actually store class names, not object ids. Also added tests to make sure it all stays that way.
c8be52b Finally! We now have mount support in OS X. Ouch.
3327dc8 Adding netinfo type and some tests
97d5ab6 eliminating some debugging, and removing a small redundancy bug in nameserver.rb
35e65de Fixing authstore to use an array for ordering, rather than a hash, duh.
c3b7d62 Bugfixes for OS X. I had to do some shenanigans on type/file/ensure.rb -- it was testing whether the parent dir was writeable on object creation, and if not it was not setting ownership and such, so i added some post-creation checks that will fix ownership if it was not set correctly at creation time.
caaa331 changing ssldir perms to 771, so non-root users can write to subdirs if they have permissions
a791d98 Fixing a logging bug that apparently resulted from logging changes a while ago.
4daf2c1 Adding apple package support, but it is very limited -- packages can only be installed, not upgraded or removed.
f37154e making a small change to the test, so failures are more informative
7c7c223 Added a test for Type#remove, and fixed the method so it actually works. I was missing every other object, because i was iterating over the array being modified. This caused the Config stuff to often fail, because objects were not correctly being removed. All fixed now, though.
72774bb adding mkdir equivalent of Config#write
e6f9163 Adding a "write" method to config objects, so that files can be easily written with the correct owner, group, and modes
0f15e8c fixing a bug that appeared somehow in port.rb, and adding mount and sshkey to the types being autoloaded
0eae739 renaming filesystem to mount
48d7fd6 Adding filesystem support, and modifying parsedtypes a bit to fix a bug where non-instance lines were being duplicated
c7ae839 Manifests can now specify node names with fully qualified domain names, too.
9b1e8d5 Accept a single file as a test to run in addition to a directory
bdc819b Remove unused should method; add more yum parameters to the type
a9fdf9d Disbale running puppetmaster as puppet until we've sorted out which files need what ownership (there's trouble with /etc/puppet/ssl right now when puppetmaster runs as non-root)
1365103 New yumrepo type for basic management of the yum configuration of one repo.
6d4e46c Adding os x group management support
791e4da Committing support for group membership management. Currently only works on Linuxes and other OSes that use "useradd" that support -G.
932fd03 commiting package test fix that i thought i committed ages ago
28602a6 Simplified as yum install can be used for both install and update
95b762b updating changelog for 0.15.1
fc98ab0 Fixing #100. I just added a bit of a hack to configuration parsing -- if a group is specified in a section that matches the name of the process, then it is assumed to be the group that the process should run as. The problem is that we are reusing the term "group" here for both the run-group and the file-group. Oh well.
5dcf303 Using differents commands with yum depending on whether the package is currently installed or not.
7e908a5 Removing ruby as a dependency, since too many packaging systems will have installed it differently
73d051f Fixing service enable/disable on solaris 10, and fixing some problems with the tests
5e86634 Converted everything over for Puppet. The Rakefile is, um, a *lot* shorter. :)
8416f21 This version appears to work well with epm stuff
fc68910 removing dos EOL chars
086050d Minor changes from Fedora Extras review
72f1e8a Don't mark puppetmaster for start by default; makes rpmlint happier
6006a5a Add little snippet on passing an additional option during system boot, but leave it commented out
6af21e5 adding sbin directory
c74fd81 Committing the EPM support. I am in the process of moving this to a common library that all of my projects can use.
271a8d2 Adding EPM package building.
805b32b Updated to version 0.15.0
92e3c1e Updating changelog for 0.15.0.
ec7d46e fixing small bug in the test code when there are no packages to test
f851be7 Adding upgrade ability to sun packages. Currently it removes the old package and installs the new one.
4d1c221 Changing the way the hosttest output is handled
29ec706 adding some extra info to the ldap test
76474ed Fixing fileserver tests; apparently they were still broken from when i changed the fileserving interface to handle links.
d7a75c5 Fixing small bug in symlink recursion
f2c8218 Fixing #94. When "ensure" is synced, it syncs the "enable" state at the same time.
aed1f11 Ooops, did not save the docs before committing.
5a47afd Fixing #98. Filebuckets now work throughout the system, and the puppetmasterd creates one by default. I have also updated the :backup docs, adding an example.
1b11697 reducing the log level for checksum warning about symlinks, really this time
454247f reducing the log level for checksum warning about symlinks
08b36cc Adding enhancement #92. Unfortunately, I was not able to write test code to consistently verify that this works, because there is too much caching internally. I verified it personally using my own configurations, but that is as good as I could do. This indicates that caching should probably be rethought, so that there is some kind of global "do not cache anything" mechanism.
97913d4 Fixing bug related to recursion testing
c6230dd Fixing rpms so they will automatically upgrade when you point Puppet to a new package file
caa3d43 fixing broken test from my previous change
fa9aab6 Fixing #82. You can now specify comma-separated tags to get run in puppet or puppetd: puppetd --onetime --tags "enhost, facter" -v. You cannot specify classes explicitly, but tags map well to classes and have the benefit of being more generic.
414d364 Supporting rpm installs when a package source is specified
8728920 Using undefined variables is no longer an exception, it just returns an empty string.
4ee395b Fixing small bug when autorequire returns an object instead of a string
2cd67ad There was a critical design flaw in the link recursion work I did previously, and fixing it required a decently large reorganization. Everything is much, much cleaner now.
02f91fc Merging symlinks back into files. Symlinks still exist but with a warning about deprecation. Fixes #93. Also the first time I have run any tests on OS X, so there are some bug fixes related to that.
b336e7e Parameters and states can now register regexes as allowed values. Also, there are (finally) tests associated with params and states, although they should be much more comprehensive.
b6d829b Fixing #95. I had to redesign how events were triggered; the transaction now individually triggers each subscription, so that it has control in how to respond to failures. Eventually, this will lead the way to error handling within puppet, but for now, it just allows us to trigger every appropriate subscription, whether some have failed or not.
782f85a Creating a single, constistent method for writing files, instead of having :ensure, :content, and :source each have a slightly different mechanism. This method also makes sure that the owner, group, and mode are always set on file creation, so extra runs are not necessary to make it work.
2dbd7e1 Fixing #96. Defaults are now set when the object is passed out by the scope, rather than when the object is created. This is nice because it also moves awareness of the scope internals out of the AST object and back into the scope.
7756f9a Fixing #97. I was wrong about the object type I had, so I was calling "type" with no arguments, which was causing the bug.
2faff5d lowering the log output for nonexistent files
eb68633 Updated to version 0.14.1
cee0882 updating changelog for 0.14.1
2351cd7 making case statements not create a new scope
54fcdbd fixing some more logging issues
0549d03 Making some logging changes, and fixing a small bug in group management on missing files
72d747b Updated to version 0.14.0
b76004a Fixing yum listing bug, and caching the "latest" value so it is not asked for so many times; this fixes #90.
3c07deb Committing the last changes, for now, to handling links. You still cannot copy remote links, but you can either ignore or follow them. I do not think we will be able to copy remote links until I have merged symlinks and files to be the same object type again.
e9e88b0 Adding "links" parameter to files, and adding support for following or ignoring links to all of the states it can matter to. I still need to modify "source" so that it behaves correctly when managing links.
1099c4a removing group ownership of the state file; I realized that the server does not ever actually write to it.
5cca870 Switching from using "evaluate" to using "retrieve" when getting checksum values, since retrieval is sufficient, and evaluate keeps printing messages about changes.
17d4b23 Fixing logging in the fileserver so it is always obvious where the logs are originating, and fixing a bit of debugging elsewhere.
df74b62 fixing deprecation notice about services using "ensure" instead of "running"
8c0a07a removing extraneous debugging
be4d3fd fixing the mode of the yaml file
f2ea9b7 Supporting variables as the test value in both case statements and selectors.
1a3de8a renaming
549bc5f Only setting group or owner on config files when running as root
7ea739d logging config changes at debug, instead of the normal log level
aae9b2a Definitions now always create their own context, which means that they cannot override elements in the containing scopes.
451ba6d upgrading to warning the message about using a cached copy
faffd69 Updated to version 0.13.6
caa7f48 updating changelog for 0.13.6
343dd08 Fixing tests so they do not chmod /dev/null to 640 (stupid tests).
1a93c82 Fixing #68. After tons and tons and tons of work, everything successfully configures itself, and the --genmanifest argument should actually work. User and group creation will not necessarily work everywhere (in particular, Puppet uses dependencies to create the group first, but Fedora complains on user creation if the group already exists), but file and directory creation should. The only downside is that there is a decent amount of extra information printed on daemon startup, as the daemon checks its config; this could maybe be seen as a bonus, though, I guess.
95856ea Okay, Puppet is now almost entirely capable of configuring itself. I have not yet added the extra tests to puppetmasterd to make sure it can start as a normal user, and the executables still fail some simple tests because they are producing output when they start (I will get rid of the output), but overall things look pretty good.
ff1df8e Remove hte fedora-usermgmt stuff. As it turns out, it's not a Fedora Extras requirement to use it; so we'll just have useradd/groupadd allocate id's dynamically
2db2317 Adding metadata to defaults
179779d Changing the setdefaults input format somewhat. It is always a hash of some kind now.
4574928 Intermediate commit; setdefaults now accepts both hashes and arrays
6d8a1dc Fixing user and group management in the config handling.
65ed766 adding a connect log to the master server
32cbc59 Fixing #70. We now have user and group management on FreeBSD.
8b5f709 Fixing bug #60. Converting nodes to use types everywhere instead of names, and adding a localobjectable to keep track of what parameters have been defined locally.
eda9d95 Fixing #64; multiple class definitions in the same scope is now an error, although using the same class name in different scopes is not an error.
56116c2 Fixing bug #73; node names now appear only once in the path
c894eb2 Fixing bug #75, providing support for unnecessary end commas.
020499c Removing all of the autoname code
8c821c0 Mostly, this is a refactoring commit. There is one significant new feature, though: overrides now only work within a class heirarchy, which is to say that a subclass can override an element in a base class, but a child scope cannot otherwise override an element in a base scope.
37c10d1 Switching setclass to use object_ids instead of class names, and adding some comments.
c5d8680 Fixing scopes and AST so that definitions and classes are looked for in the scopes, instead of in a global list
ee818a9 Adding some debugging to list the states being changed when in debug mode
63afa37 Fixing nodes so that their paths are printed correctly
5056054 Removing timestamp debugging
b119a72 Fixing output when user/group are not found
772c7c8 Adding TERM to the signals being trapped
503ad38 Fixing bug #72, where trailing slashes break file sourcing
043fc33 adding commas to each line
d06cd3f removing the initial syslog dest setting
f6ca82b Updated to version 0.13.5
85e4d31 adding changelog for 0.13.5
2dffbee Adding redhat service type, to support enabling and disabling a service
7e5cc76 Fixing package types so you can specify the package type manually in a manifest
7806618 removing extra error statement
6e26a73 adding passwd converter
3aff15e Updated to version 0.13.4
1f05ad0 updating changelog for 0.13.4
cfb0e36 updates
89856ec Adding a bit more logging
82e02eb Fixing bug when creating containers with parents
31df227 Generate an error if the pattern for an import statement matches no file.
beef01c Properly figure out when updates are available. Previously, packages would neverbe updated because 'yum list foo' first prints the currently installed package. Now we use 'yum list updates foo'
3ac5cd9 Incorporate initial feedback from FE review
68aa302 Fix failure of test_importglobbing in test/parser/parser.rb
70d2379 Enable passing --parseonly from the command line
1ebb416 Adding single-quote syntactical element
1fdb962 Changing transactions to be one-stage instead of two, and changing most of the type classes to use "obj[:name]" instead of "obj.name" where appropriate, because "obj.name" might be a symbolic name (e.g., File.unlink(file.name) will not do what you want if file.name == "sshdconfig" but file[:path] == "/etc/ssh/sshd_config")
5f8d615 Removed some of the autorequire stuff from :exec because it created untenable require loops, and created a test case for some complicated exec + file recursion. The test case fails, and I want to have a clean committed repository before i mess much more in trying to fix it, which might actually not be possible.
6cc8157 Duh, removing some debugging
5f4335f Adding logoutput parameter to :exec
89702d8 Fixing symbolic naming bug where symbolic names were being ignored in some cases
7d15fe1 Updated to version 0.13.2
037b7ac Changed the parsedtype definition of exists(), and fixed a few smaller bugs. Last code commit before 0.13.2
6fe01ce Tracked down a few other bugs; everything now passes on debian in preparation for 0.13.2
8602932 Changing "answerfile" to "adminfile", adding "responsefile", and autorequiring both.
d1cd443 Fixing users so that they can use a group created by Puppet, and they also now autorequire that group. To do so, I modified Puppet::Util.gid, which required that I fix Puppet::Type#merge to support merging managed and umanaged objects, which required fixing a bug in Puppet::Type#managed?, and I also changed the ensure state to only default to a value, when the object is managed, which required that I change the defaults system to support default procs that do not return a value. In other words, lots of fixes for a smallish problem, but we are much better off now.
4df3468 Fixing the order of arguments when using admin files with sun packages
20b65e7 Some important bug fixes in the parsedtypes types; this all started from the submitted bug today, but I added :absent support to most params.
6cfee76 Committing the initial ldap support -- puppet can now look up node configurations in ldap. The test scripts currently only work on my home network.
1994263 Adding --enable/--disable locking for puppetd. You can now disable puppetd from running by creating a lock file, which is useful if you are testing a configuration and want puppetd not to run for a bit.
798b3be Adding a general "check" mechanism to :exec, so it is now terribly easy to define a new check to perform, converted :creates and :refreshonly to use that mechanism, and then added :onlyif and :unless as new checks. Also added any files they mention as autorequire files.
376725e Adding --loadclasses option to puppet
f098485 Correcting some path problems with symlink, and changing "target" state to "ensure"
3f15cb8 Fixing :target reference in pfile.rb
9508bd0 Correcting some path problems with symlink, and changing "target" state to "ensure"
64eafa8 Updated to version 0.13.1
a456c4d updating alias docs to pass ReST checks
1a05ed2 updating changelog and docs for :alias
89d37f6 Fixing some problems with cron tab management, and creating Puppet::Util.{u,g}id methods.
96388cb Fixing locking. It apparently was not working on OS X, and I was not syncronizing access in threads -- i assumed locks themselves were a sufficient sync point.
2be25d5 Making the language name a real alias. Now all objects in Puppet support specifying both the name and the namevar, or just a name and having the namevar set.
7f7b5c6 Change in how logging is defaulted: by default logs go to :syslog, unless the user explicitly gives at least one --logdest argument, in which case logs only go to the destinations the user gave.
b13b5ed Set the Release tag in the spec file to 1 when the version is changed
8c02ffd Adapt specfile to the fact that puppetmaster now automatically runs as user puppet. Add default config files that send logs to /var/log/puppet.
d629a80 Fix version in last changelog entry (makes rpmlint happy)
44071d0 Updated to version 0.13.0
2cb5cb3 Updating changelog for 0.13.0
387db24 Adding answerfile support to sun pkgs.
2ce061a adding some documentation
cd7a637 removing errant warning
ccd0121 Fixing small problem where checksum retrieving did not look in the cache; this was only ever a problem in cases where checksums have no "should" value set, which is generally only the case on the fileserver, but it caused the fileserver to replace checksum values on every retrieval.
8eab733 Fixing the conflict between ensure and source. Ironically I had already made sure there was no conflict with "content", but I had forgotten "source".
adda8f0 Checksums now get correctly updated for both the ensure and content state when those states are used
8e4cf22 first bug fixed, where sources were not updating the checksum
58db0ef adding keyword
b03635b adding keyword
01072a8 replacing all occurences of "is_a?" in the parser with "instance_of?"
7ca3d3d Fixing bug that occurs with only one argument
195f2e9 wrapping all work in a single rescue clause
59992b5 adding initial ldap schema
0ba9d16 adding vim syntax stuff
a5d2404 Simple emacs mode for editing manifests; only does pretty colors right now
b98e65f There is now full support for configuration files, and the entire system has been modified to expect their new behaviour. I have not yet run the test across all test hosts, though.
f1ffc34 Configuration parameters now require (and have) descriptions, and a set of configuration parameters can be converted to a configuration file, a manifest, or a component. All I have to do now is integrate them into the executables.
6affe22 Committing both the finalization of the config code, plus all of the code necessary to get basic isomorphism from code to transportables and back. Mostly keyword and autoname stuff.
59c7b02 Fix snippet_componentmetaparams test
39d33ca Temporary commit; configs now can be converted to manifests
4ecfa7b Config files now seem to work, so I am ready to start incorporating them.
9114cbe committing test code for bug lutter found
d0436f1 Changes in lie with Fedora Extras requirements
56bf12b Fix processname tag
7d711c0 Allow passing of options with 'once'; fix processname tag, add config tag.
5590e3e a couple small changes; the most significant is the addition of a class-level "eachattr" method, to avoid all of the calls to attrclass and attrtype
30bf65f Fixing a significant performance bug in file recursion, and trying to help performance a bit in attribute handling on types
d5af359 Rewrote client init script since puppetd is now a proper demon.
6637bb6 Install bin/puppet into /usr/bin/puppet, not /usr/sbin/puppet, since normal users are supposed to be able to run it
931c159 Fix rpm packaging; include conf/ in tar ball, use conf files from tarball in spec file
4ada6af Fixing class storage -- it was not working for nodescopes
8db35ec Caching Time objects instead of numbers, since Bignum does not seem to be YAMLable
96b761b Fixing waitforcert so that the client can actually add the certs once it receives them
c7f9942 Adding release tag REL_0_12_0
cf82cfa Updated to version 0.12.0
282cfcf Updated to version 0.12.0
1186069 Small mods to the packaging stuff
87904d3 RPM release is almost entirely there, it just needs to be integrated into release management
9b2afcb Fixing some logging issues
ae2575b Adding the event-loop stuff to the repository and switching to using it. Also, breaking many classes out into their own class files.
18e8e74 Committing most of the scheduling stuff. There is still a bit of work to do in terms of how puppetd interacts with scheduling, but the bulk of the work is done.
258114d Modifying docs, and adding scheduling hooks
0cb51f3 Fixing a small checksumming bug, reorganizing the client stuff a bit, and adding freshness checking for the configuration, so the config is recompiled every time nor is it downloaded unless it has been recompiled
f49b103 Updated to version 0.11.2
c372a7d modding changelog for 0.11.2
6bab167 Made lots of small changes, mostly to help usability but also fixed a couple of key bugs
ed39be9 Fixing most types to allow no statements
3d458ef Updated to version 0.11.1
c3df525 modifying changelog for 0.11.1
060b8bd Adding openbsd packaging support
ada3aee Fixing problems where objects were passing @parameters[:param] objects, instead of specifically retrieving the value
f36c7d1 Updated to version 0.11.0
3700b37 Adding an "ensure" state where appropriate, and significantly reworking the builtin docs.
92a780a Added "ensure" state to some classes, and added infrastructure for it to work elsewhere.
83906a2 Adding sshkey class plus tests, and adding "aggregatable" methods to type.rb
c67fb7b Adding another host to the test lists, adding some test data, and modifying how hosts parse
ad9d365 Adding a bit better logging and checking to file access
87b3bb1 Moving ast classes into separate files
1d4638a Added "finish" method, using it in Type.finalize, and moved autorequire and setdefaults to it.
a6e367e Changing host and port aliases to also create Puppet aliases. This involved futzing around with the attr* methods in Type.rb, to make sure states are always checked first.
c8b6401 Fixing up the parsedtypes, fixing Type.eachtype to ignore structure types
bbf2c54 Adding /etc/services support
0c17149 finalizing cron and host management, hopefully
df6ff9e Abstracting host support so it should easily support other types
5309479 Abstracting host support so it should easily support other types
3f15e38 Adding initial host support. I can promise that this will soon (hopefully almost immediately) be abstracted to make it easy to add new file types.
f420135 Converting transport format to YAML instead of Marshal, and caching the file in a YAML format, also. This required a significant rework of both Transportable classes. Lastly, I am also now caching the list of classes in a class file in /etc/puppet.
8aa331d Adding further notes about openssl
4092a78 Fixed a couple of warnings, fixed a critical bug having to do with case statements (where there is only one listed option), and did a couple of other cleanups.
c5782df Adding "content" state to files, and string interpolation handles escaped whitespace characters.
b0ea70d Adding 0.10.2 stuff
6b6c49b Updated to version 0.10.2
1cf05ff Services now work at least somewhat on solaris 10, and service testing is pretty different.
4c4f530 Fixing dependencies to not depend on file order. Added Puppet::Type.{finalize,mkdepends,builddepends}
21410a2 Fixing documentation generation, and fixing aliasing so that objects can safely be aliased to themselves
29b00fb Adding "alias" metaparam; you can now create as many aliases as you want for any of your objects.
411ab22 Adding autorequire to files, and added the cwd to the list of files to be required for exec. Also, exec catches inline files and autorequires them.
97fb6c9 Adding generic autorequire mechanism, and thus removing it from exec
11b5463 Adding a requires? method to types, fixed the bug where exec fail when Puppet is downloading the script to execute, and modified "exec" to autorequire any managed scripts
932b783 Updated to version 0.10.1
854f16b modifying changelog for 0.10.1
89d0050 Adding Sun support and fixing the last remaining bugs related to the daemon changes i just made
45ac512 Supporting puppetmasterd running as a non-root user, and doing some basic message cleanup
45c91e3 Adding some extra feedback
7616289 Fixing init path default
e5ac196 Adding some consistencies to the executable tests. All exe tests now pass on OpenBSD, although the only real problem was that ruby was in /usr/local/bin.
dccafc7 Updating Puppet to work with the new Facter
b7974b5 Updated to version 0.10.0
48031dd Describing 0.10.0 changes
48ba030 Modifying hosttest
f00a7db All tests pass now, although the lack of service support on os x means that i have now disabled services on it
4275227 updates
cbf10c5 Merging changes from the head of the rework1 branch, r 784
23f982e Undoing the merge that happened in 785
1d73973 Merging in refactoring from version 774 into version 784
3ba696d updates
cb51688 converting waitforcert to an int
cedefab adding ftools require statement to install.rb
7594411 Adding a host test task
86cc467 renaming the module, so it behaves better with people's svn clients
2994cbc fixing rakefile
3b9c9be Updated to version 0.9.4
6af79cc Removing tests from the list of tasks
e611f2c adding some better readme stuff
b532a30 adding things to the change log, and modifying the order of the steps
584652c Disabling most documentation generation except for the API docs, and wrapping the StatusServer in the xmlrpc check
0e0fdac Updated to version 0.9.3
e2e2fb3 some updates to the typegen stuff, even though i may still not use it
5302921 Fixing two reported bugs in cron jobs. Cron jobs correctly change when fields other than the command are updated, and they do not continually refresh when the command has trailing spaces
592c24d adding some comments
f9f84bf removing "host" as a keyword; it was an alias for "node"
4eaf13a converting storage from Marshal to YAML
3c14db1 adding Util.lock, and switching storage to using it
5ce5b95 removing any direct references to /tmp in tests
84bf289 fixing files being put directly into tmp
a03b03f removing ruby shebang at the top of all of the files
2a5bbd0 final updates for 0.9.2
58ef35d updates
dd727ef removing marks
9f942b0 fixing tests to work from any CWD
58c0df1 fixing incredibly annoying bug where os x returns stupidly large uid when uid is below 0
42c077f updates from os x
f815654 updates
5082132 adding cfengine module, which required passing the cfengine classes all the way through the stack to the scope
c205bf6 fixing filesources so that the first found file is copied, and adding a test case
6960034 fixing puppet to default to using the console for output
d5bd1bc Mostly fixing exec so it either captures stderr or runs as a user; Process.euid was not working correctly
a4562bf Lots of refactoring, and added the capture_stderr method
42a9d9a Adding "isomorphic?" method to classes, and testing for isomorphism before throwing a conflict
300a163 Further progress towards the next release. Lots of small bugs fixed, the paths look much better now, and Transportable is much cleaner.
14d8186 Making paths work a little more intelligently
0335743 adding config file stuff, but not using it yet. I have decided to release the next version without them.
ba76eb2 Cleaning up tests resulting from the changes to the parser
e605a5c The language now verifies some resemblance to closurehood. I now only need to fix the library to expect this behaviour.
526deef Fixed merging of state values, but I have not yet solved merging of parameter or metaparam values, since they are quite different.
9e1c63a Protecting from bug in Syslog, and fixing some more log messages
76176a9 central logging is fully functional now, but it is painfully slow, so it is disabled by default
b6c63f6 Central logging now works, although there appear to be a few kinks to work out.
0ae5e33 Adding logging methods to all Puppet::Element instances, and converting all instance log statements to use those methods. Additionally modified logging to take advantage of this by including the path of the logging object in the output. Logs will still need some cleanup to avoid duplicate information.
0d3db79 adding tags and path accessors
a8645a4 Further small bug fixes towards running puppet on my network
df8dbba fixing sources so that they always have a corresponding checksum state
e8912d5 files and directories are now created as the correct user and group if they are set
1b74e8e The Puppet::Util.asuser function now works; had to slightly modify user.rb to make checking work. In addition, exec.rb now takes advantage of it. I also decided to make a small change to type.rb -- validstates now only returns state names, not names and states.
32d89ba fixing certmgr tests
f732880 Getting rid of the tc_ prefix to test cases
8fe558c general cleanup, as i move towards running it locally
5ab12f9 fixing path to facter
f036778 Apt-cache was showing more information that I thought, so I had to redo how I was collecting the most recent package version
a232e5c Made tweaks here and there to get it running better on my local network. I am inches away from that happening. All tests pass.
a6d0292 adding better docs to packages
3cd8ee9 "latest" is now a valid value for packages, and yum support is also included
66db3d8 making service changes; it is still basically non-functional except in the degenerate case of using "init"
194dab3 Adding some semantic tagging. It is not exactly full-featured yet, and it is not used at all, but it was sufficient for some proof-of-concept stuff in preparation for the conference
55d7bbd adding tag support to scopes and the transportable class
e563189 switching test classes back to modules -- making them classes causes too many empty tests to run every time
9d3aaad removing the redundant pfile from the pfile state file names
ed42371 Switched @should to an array, so all objects can now handle that. I have not yet gone through and done the other cool things that can result, but that will have to wait until tomorrow. Also, I moved all of the pfile states into separate files, since the file was getting unweildy.
6af0e0e added overrides ability
0d6241c switching all relationships to be centrally maintained and to use symbolic references, rather than literal ones; also going through and making all tests pass again after mucking with services
a96bdac Okay, services are now managed, um, entirely differently. I have the beginnings of a system for supporting different service management frameworks, although I currently only support <nothing> and init scripts
47ba186 adding a test for includes
9464224 moving specific packaging support into separate files
f48f14a fixing behaviour when files are missing
5bb8c4a fixing output in noop
abcac81 Rearranging the packaging support a bit -- it is now more clear and significantly easier to understand, maintain, and enhance.
8211df0 Many, many changes toward a completely functional system. The only current problems with my home config are that apache's stupid init script does not do status and that packages are not working as non-root users (which makes sense).
d20ac8e Hoping this will get rid of the directory being printed
4c13c10 Nodes now support inheritance, for better or for worse.
781c69b The new "include" syntax works now.
400b103 fixing "ignore" documentation to parse RST correctly.
5590148 Okay, all tests pass again. The work done on nodes will take a little while to clarify and such, but it should work pretty well.
f7d9b83 I am still somewhat in mid-change, but I have made the biggest changes to making nodes work correctly. The core code works, but I still need to fix my various test cases
03f5733 adding a ParsedFile class to handle figuring out whether a file has changed
f757556 converting tc_relationships.rb to the test base class
5dc3cb0 Okay, significant change -- classes no longer accept arguments (which makes things simpler but encourages the user of global variables, which is bad), and classes are finally singletons, meaning they will only ever be evaluated for each node a single time. I still need to make nodes work correctly, but that is going to involve modifying the parsing system and a bit more
0747b4c adding stinkloads of comments to ast.rb (I am trying to go through and better comment my code over time), refactoring some of the AST classes, and working towards a more sensible class/definition/node distinction
d6982d5 adding some new language tests
48155b8 added log, metaloglevel and @metaparams to support setting loglevels
041ca4b switching log.rb to raise Puppet::DevError events
16c9f83 My cfengine2puppet config now entirely parses. The biggest problem I ran into is that my glob-based parsing was only returning the results of the last parsed file, instead of collecting all of the results.
23d3c93 adding --noop to puppet executable, and removing some extraneous comments
a345931 Successfully parsed my entire converted cfengine configuration; these are all fixes for bugs i found as a result. I have not tried to execute the configuration yet.
a8bdada Users and groups now work on OS X. I had to make some key changes to how transactions and state changes work -- the most important is that it is no longer an error to try to sync a state that is already in sync. I could not find another way to handle all user states being out of sync but the first state actually syncs everything.
6654c4c fixing users on normal machines
106d397 Users and groups now nearly work on normal machines and on os x, and I think I have a decent platform for expansion to some of the other important elements like hosts (probably most important after users and groups). Some tests are still failing on os x, because netinfo sucks, but I will hopefully be able to figure out a solution soon. Stupid OS X and NetInfo.
42deabb all tests for users and groups pass again on fedora, debian, and solaris
e0d1d31 temporary commit so i can move to my workstation; groups and users are way b0rked
29c291a Creating a "change_to_s" method on State, so individual states can override and and determine how they get printed
80a2808 Cron is now fully functional and tested on 3 platforms. In order to make it work, I had to do some modifications to TransObject#to_type and Type.create, but all tests pass now. Type.create is now handling errors on creating objects, so if you try to create an invalid object you will just get nil returned, rather than receiving an error.
e25e8c6 adding keywords
aebfef0 adding keywords
11d3d24 cron is working, but i want to write quite a few more test cases
036ba7a small fixing to merge(), and changing output of statechange
093963e finishing up merge method
ac0454a making "Type.new" private, and switching to "Type.create", so that i can merge new objects with existing objects and such; converted all files, and tested them
f7116e5 switching FileTesting to a class, and modifying test suites as appropriate
7861269 removed directory output
bf701dc adding extra checks to make sure networking is secure, and refactoring a heckuva lot of test
0c97bb1 fixed problem using arrays
897de46 cleaning up tests a bit; mostly just making sure tests clean up after themselves, but also doing some rearrangement and fixing a list() call
6767dd2 debugged ignore in fileserver, added tests to ignore tc and fixed server.list in tc for filesources and fileserver
39aaa99 fixing some tests
6c6ff03 moving some testing and debugging around
192c07b fixing non-netinfo group
9ebb767 fixing non-netinfo group
669ae38 modifications to eliminate code duplication in state creation, mostly to support cron
ae00500 preparations for supporting netinfo in users
610f95c switching groups back to having namevar be a parameter instead of a state
2a6710b fileserver still has a bug
ec66034 added ignore to fileserver and pfile
3d5f5a1 adding cron stuff; it does not work at all yet
0d3024f adding globbing to import
5438eff removed comp.sync and replaced system mkdir -p
79961e1 added test case for ignore
157953a added ignore to pfile
51948bd adding example configs
d43dc86 tracked down some sticky bugs related to having false values and empty strings; all fixed now, and all tests pass again, including the new tests that cover the bugs i found
aca4cf8 fixing error handling so that failed objects are completely destroyed; they were receiving events even though they were supposed to be gone
0a4e392 fixing component flattening and sorting; it was not working for cases where objects inside of components had dependencies from other components
58ca9d1 adding snippet test to verify correct behaviour with missing exec path; also, adding "creates" parameter to exec
f9df523 intermediate commit so cron is not loaded
4dd1dd8 adding more comments from talking to andy
3306cc7 incorporating comments from talking to andrew
29fa170 incorporating comments from talking to andrew
d0eb566 some small fixes
ee1eba2 small updates
f69abc9 adding cfengine to puppet parser, but it is not even remotely close to functional yet
8f7b191 fixing groups again after getting them to work with netinfo
da6590d group management now works on os x, although it is six shades of really nasty. Netinfo is a nightmare.
3726cee adding debug setting to the top-level test class
99db7bc reverting changes in the reverse order of what i executed them
8f0ef3f removing debugging
2213430 making states capable of being the namevar
923226e all tests now pass on solaris 10x86; i had to do some stupid hacking with base64 for it to work, and i am working getting a much better base class for all test classes
edc392d adding a break if randomization takes too long
4cc12a8 finishing up user and group support for now
9e4ed0c rearranging some documentation
24b1c67 adding scopetest
b77d295 adding user and group classes (although user class is not yet functional), and added "is(state)" and "should(state)" methods for retrieving the respective values on a specified state
4f2812a changing rollback() to do event handling also
72638e6 adding simple newcomp() method to base test class
795a5a0 adding all of the work necessary for tidying
f7a5f87 removing DEFAULTPORT stuff
21244f4 fixing small bug in setting default port
c0c958b changing some documentation methods around
3fb6f49 rearranging puppetdoc to not separate states and parameters, and to allow undocumented states
75ec054 committing initial tidy stuff, so i can move to the laptop
0d01770 cleaning up obviated methods
747c3f6 defining $name in each component scope, and adding test case
f49ffa3 defining configstatted
750b880 removing if-related keywords
008cea5 fixing error calls
e1bf0e1 fixing bug where remote server name is ignored
e1de002 Fixed small bug that caused the config files to be parsed on every connection
5c0fb02 fixing documentation for file source state
6a96fcc adding file reread to master, although it is plenty hackish
cff3a5b fileserver config file now reloads when it is more than 60 seconds out of date
998b415 correcting documentation on autosign in puppetmasterd, and switching the autosign.conf file to use the same authstore as fileserver.conf
7f274a4 catching a potential security problem -- requiring that "path" always be set for a fileserver mount
8a99636 adding a "--noop" option along with a test case for it
f65563d changing default hostname to "puppet", and adding --parseonly option along with a test case for it
0629065 fixing puppet to use correct method and adding a real test case for it
82ac86e changing default manifest location to /etc/puppet/manifests/site.pp
3087f85 changing version number for beta
e28e11b removing need for zip in rakefile
fc20167 UPdated rakefile
914764b As Christian requested, I am no longer downcasing facts I receive from Facter. Also, removing some outdated files
eab7314 bumping up the default log level for changes from info to notice
cc48367 I did not have good puppetd tests, so I missed the fact that I was calling the wrong class in puppetd. Fixed.
65d1375 disabling print of library warnings, since webrick and openssl have far too many warnings for comfort
cdfaa5e adding RDoc::usage documentation to all executables
f279535 This should be the commit that brings us to Beta 1. All tests pass, although I get some (gracefully handled) failures in tc_metrics.rb, and there is now a config file for the fileserver module, including authorization specification for it. I have also reworked error handling in the xmlrpc client and server so errors should propagate more correctly.
28be88c Adding authorization store, initially just used for file serving but eventually for all authorization, most likely
814a9b0 adding config file parsing
9ec321e recompiling parser after removing extraneous debugging
773be96 Added GPL license
48a2e0f making array-as-name work in the language, and adding some more test snippets
66b3355 Certificates now verify!
386ebee replacing if statements with case statement, and adding defaults for both selectors and case statements
583a9c6 remote filecopying now works
5b20c92 Have done a significant reorganization of how clients work, also, along with some interesting trouble shooting on components
ba51e70 fixing checksum generation -- i was causing some weird bugs by using the same indicator in different cases, and i added a test for invalid checksum types
fb3cff7 small comment change
dde841f Created a Handler base class for all of the server handlers, which allows a lot of the manual work to now be automatic
49e3e37 splitting normal file tests and source tests into different files
a8fff85 ignoring remote file owner when not running as root
f68fe00 moving all server handlers into a specific server subdirectory
129dad7 removing obsolete file
51294a0 moving rake file to the trunk dir
6029ef7 Moving all files into a consolidated trunk. All tests pass except the known-failing certificate test, but there appear to be some errors that are incorrectly not resulting in failurs. I will track those down ASAP.
e87eb58 adding test to verify require does not kick off an event
4741eef Execution order is now based on dependency relationships, and those relationships correctly propagate up and descend into components. There is also an event test suite now, along with a (currently simple) component test suite.
63309c3 fixing test base class
f026884 just fixed an incredibly ugly bug where @parent meant both parent array and parent class
78939cc passing file and line to all objects
51ffd6f trying to create a testing base class
54e5eb4 moving
4f0750b adding
9f84742 all tests pass except a certificate test i do not know how to fix
163db7c a basic first test of puppetmasterd now passes
a3e03e2 all non-executable tests pass now
d49a98e further progress towards passing tests
2be10b5 all tests pass except those related to puppetd; i am going to significantly reorganize how serving is done
6eac358 updated version number to allow gem install
8d71cd9 Added rake for Puppet, '--version' to puppet and test case for Puppet.version
cfaee58 more progress towards a functional daemon
3cb04cb setting up http to log to a separate file
adc10d8 setting up http to log to a separate file
c7380c9 renaming
cb1956d adding daemon helper module
bb4b5a5 done a lot of work on certificates; all tests except one puppetca test pass
e2e2474 removing obsolete files
0f7d185 fact.rb is obsolete
af1b979 function.rb is obsolete
fc0ba4b fixing directory mode creation
5bcae96 renaming again
2687652 renaming openssl to certauthority
aacd780 removing comments and making @csr a class attribute
4b5c5bf fixing error output
c0b0975 adding creation rollback
f654f2d returning transaction from client.config()
a6a1148 all tests now pass on os x
f3c1487 adding better error handling for missing paths
77e1cf0 fixing verbose output to be better and easier to manage
9c7c71c passing state, so more info can be extracted
afcb2ee adding a bit more output
bc3a433 committing recent changes for testing
7b14e39 a bit of refactoring, and a bit more functionality
0fce775 okay, switch all cert management to the library, instead of using the openssl binary
a1d206a moving
6ba0e10 certificate management; yay
de4e5bf oops; removing errant notice msg
223cc9f cleaning up the defaults system even more
74dac8f adding some consistency and tests to the whole puppet defaults system
8bf85e2 adding tests for puppet defaults
d14e1b4 uh
4af2559 renaming to avoid name conflicts
5fa0c20 all tests pass again
edc2842 local filebuckets are now tested with files
e041c8a basic filebucketing is now working
cf37c06 Moved documentation to project website.
9f2aaac more changes to documentation
952a76c working on documentation
54895da Updated README, moved the old one to documentation/
2d1e643 Updated doc/big-picture doc/structures, Added rst formating to puppetdoc, and added doc strings for types, states, params, and metaparams.
700b965 dpkg/apt package installation and removal now works
e685ddb fixing statefile creation
01666f6 fixing lib loading test
075ffd7 making changes necessary to pass tests on all available platforms
b5f6a54 fixing solaris packaging
ffe318c fixing packaging to work with rpm, too
64b55c1 creating FileTesting module in puppettest.rb, and getting recursion working with symlinks
9d8f754 adding some attributes to errors
dcbbef7 adding symlink back as a separate object
e078329 adding symlink back as a separate object
60965c5 removing silly message
f624cd5 making the console output slightly less redundant
848df27 okay, last try on sources hopefully -- no failures, and basic functionality all seems to be working
cc67845 fixing package listing
326b4ad fixing exec tests to work with new event stuff
fa6569d okay, sources seem to be much more understandable here -- only the recursion function is recursive
5351eb9 adding some error checking
60e02de not dump/loading for local client/server
8ec8c8d sources now pass all tests
a33d5d4 everything seems to actually be working now, including getting the correct file list back
2d34f8e Ha! finally got recursion and sourcing working together
bc38169 redoing how arguments are handled in type.rb -- it is much cleaner now
973385f first versions
c577e57 reducing debugging
99eedb3 reducing debugging
8f718da recursive file copying now works even with some limited number of errors
aa59473 okay, file sourcing actually seems to work now
9a5477b checkpoint commit
0e94644 moving setpath to parampath=, as a param method
3a67efa adding "=" to metaparam methods, and allowing types to use methods for params
de91dbd temp commit before i change the whole way that i am doing source + recursion
9ba72f5 removing, since pfile now has link functionality
311218b removing, since pfile now has link functionality
6f4f821 downcasing the values of all facts
b1f3fb8 switching facts to be auto-provided by the client
357afbb removed type.method() syntax, and replaced it with Type { default => value} syntax -- i still need to add test cases
f38bdef changing path stuff to be service-specific
84f721d modifying failer stuff
3d725d9 adding more validation methods
f2b6762 reducing to one statefile definition
ad9913b converting debug() back to Puppet.debug()
13945c5 converting debug() back to Puppet.debug()
668b9de converting debug() back to Puppet.debug()
c04b337 converting debug() back to Puppet.debug()
3c4181c adding methods callable from language
88071eb making rpm the default package manager for all linuxes, with exceptions allowed
ca87010 defaulting to rpm for everyone i don't know anything about
ebe779f adding rpm as the default type for Fedora
fbafa84 updates
b9c064e Updated install script to include all bin files.
96c37e3 using old name method, since it is required to make names unique given how classes currently work
e97e2d9 fully qualifying warning method, because it is not being imported for some reason
a984d66 disabling metrics tests on machines missing RRD
78bcfdc adding path stuff everywhere, although i had to keep component names kind of funky
99a9f4b adding link functionality
d6e2102 toying with some doc stuff
3f9bb25 removing an obsolete VERBOSE setting
5ff4b02 removing some debugging
bf09132 lots of refactoring
cc78949 in the middle of a bunch of refactoring; committing so that others can try to replicate the segfault i am seeing
1f2c866 doing some refactoring
e19ca97 converting to "include Puppet" and not qualifing output methods
8177700 hopefully, finally resolving recursive file creation problems
01a9905 moving namevar translation to a method
fffc09c swapping console colors
2062aac changing comments
75e27cf cleaning up bugs in the tests, and adding more error checking around the bugs
0417fb5 adding refreshonly parameter
6e9975c found a bunch of bugs in Puppet::Storage, plus some bugs in how file recursion was being tested and thus some real bugs in the system
256b84e adding a to_s method
d14dc32 fixing storage class; it was not actually correctly retrieving state from disk
96f3980 adding Puppet#recmkdir utility function, and making sure Log and Storage create their own files and directories as necessary
649d59a adding some more tests for recursion plus checksumming, because they are somewhat incompatible for directories
cb95dc7 ok, verbose => info
459287c duh, somehow added Blink calls in there...
600f272 adding cwd parameter to exec
4157fa0 exec stuff all works now, end to end
2c1f637 fixing some nasty bugs related to parameter checking
05d59fd fixing a nasty bug related to recursion and nonexistent files
5b7fd63 fixing some nasty bugs related to parameter checking
9e0ab28 adding string vs. symbol testing
8f1da62 adding logdest config
cf817e7 changing Log.destination to Log.destination=()
d36b4c0 disabling debug by default
420062d changing Log.destination to Log.destination=()
c718044 adding the exec stuff
3441b82 finishing rename of file class
f250d92 renaming to remove naming conflicts
26bc12b further output cleanup, and fixed the problem with tc_server.rb leaving sleeper processes lying around
bb7e283 fixing debugging to severely reduce output but allow it when debugging a specific service
c16ca53 changing warnings to debug
00343e3 basic rpm stuff now works
2b2975f fixing metrics tests to work with everything else
0ac91ef correctly returning events
0c4254a metric testing and graphing now works in the library, although nothing has been done in the language
573d301 adding some more tests for loglevel stuff
0ba9d71 adding rpm as RedHat package manager
b6b1f5a logging now exactly supports the list of levels that syslog supports, and multiple destinations (syslog, files, and console) are now supported
e3c3283 renaming message.rb to log.rb
2b3b15e temporary changes to prepare for a rename
8395639 puppetest.rb should probably be puppettest.rb
cd48af7 renaming blink to puppet
60783f0 renaming blink to puppet
8f95084 renaming blink to puppet
6f07413 you can now at least test for whether a package is installed, although you still cannot do anything if it is not -- the barrier is knowing how to get the package
65c2a69 adding validparam() to Blink::Type
500a135 fixing file.rb so it works on Darwin, also
90b9b2d updates
3f0687b updates
5324062 adding new classes and tests
0dad57a md5 summing now works, all the way through!
d1f2187 checksums now work, but not all the way through yet
18d755a Rahh! component dependencies now work!
922994e everything passes all of the tests, but i do not think the component-level metaparams are working
cdfdfb9 adding some more tests for Blink::Type
d42efbe done some more work on making components act like normal objects, but now i need to figure out how to spread events up the tree, rather than just point to point
0ab9685 dependencies now work, although you cannot yet specify them for components
2b97b47 there are now explicit tests for transactions, including rollback, and more tests involving querying
b46135f adding simple query syntax stuff
7fecad3 i now have basic events: you can only specify simple object types as requirements, but hey, it works -- refresh() gets called
02f1185 renaming events to event
d70229b update before rename
c0d86a4 intermediate; no extra functionality yet, but moving away from discussing namevars outside of a given class
d86e479 All tests pass again, and i have added Type.allclear to remove all existing type instances, thus making it much easier to run all of the parser and lexer and then server tests; i have also added remove server tests
ebc02a8 okay, everything works again, although it still might be a touch fragile
5477f36 i am giving up on fileparsing for now; it does not work yet
576a031 okay, bin/blinker works again, and i have modified both client and server to be a bit easier to use non-networked
03741b4 we now have networking it is very basic right now: the server gets passed a file name, and the client gets passed the server to which to connect. The client gets its config, evaluates it, and exits
4a4438d okay, implicit iteration now occurs at least at object definition time
4a9c1a2 enabling mucking with debug and noop
f91451d yep, arrays are always passed
d0d8df9 final fixes on passing methods through to types
3a07a4d typesettings now correctly pass all the way through and can only run specified methods, using "allowedmethods"
12418e1 the tree transformations work throughout the whole system now
f9a223c transformations from the client through to the transactional execution now works!
00a620d unmoving
135134c updates
4da3b51 moving
259692c moving
3b33738 switched to just passing scopes around, instead of passing the interpreter object around
529b9a7 file recursion now works
4e03ed1 i can now execute simple scripts manually!
ec88acf i can basically actually do work now
42dadad moving
817f571 adding lots of verbosity, and starting to actually make sure things execute -- tests are failing, tho
2cce619 basic components now work
49da910 we now have nested scopes, and we've got the beginnings of components, although many tests are currently failing
7689d19 simplifying argument parsing in Blink#message
08d4260 initializing @noop in element.rb
865dffe dealing with having moved the examples to the language area
a1a7ae4 moving to the language tree
85b9f91 everything works again, including components
9ea0c30 making components work
1f95fe2 moving component.rb to type/
7df572b removing most functionality, since type.rb already has it
565554f finishing reorganization of base classes and such; there is now a clear tree heirarchy, with parents and children -- all tests pass on the types, but there are still some issues with client/server stuff
9843da6 cleaning up object tree and adding a simple virtual base class for both types and states
d0c6b0c adding transactions
89d2381 moving event info out of type.rb
3c6c0f7 removing elements.rb
e452f00 preparing to remove elements.rb
cf08be1 renaming statetree to elements
b6d0f0c first version of finalized base classes
f984192 noop seems to basically be working, but i need to reorganize the whole type/state structure -- that is starting after this commit
c01bc81 using the example syslog.conf instead of the one in /etc
57194eb adding some example debian configs
6cd71f8 filetypes now support multiple record types, and newlines can be escaped
7378765 completed the first step to enabling multiple record types in filetypes
490854a the client now executes "evaluate", which might not be a good thing -- i am getting failures if files do not exist, for instance
6127e43 filerecord.rb: duh, fixing a small debug string printing bug
371235b reorganizing the FileType/FileRecord into a base class (TypeGenerator) and basing them off it
7deba97 adding typegenerator baseclass
b18d071 fact.rb is no longer a subclass of Blink::Type
43a63db fixing filetype and component to take into account changes type interface.rb and type.rb
a16493d type.rb: adding methods to simplify type initialization, and adding eachtype() to simplify testing
69a1276 adding some tests on the interface methods in Blink::Type
de360c9 renaming objects to types, since they are just subclasses of Blink::Type
b872b72 renaming types to type everywhere; all tests now pass
a50d461 changing types to type internally
c0bc63f moving types to type
b85ac7b renaming types.rb to type.rb
9d163d0 changing Types to Type
68409ef adding
cb5f54c deprecating interface.rb
974969d final changes before deprecating
f8b08b2 adding an fqpath method to state.rb
ae13f00 adding name information and a FileRecordState class
a489639 moving some methods around
14c2308 adding markers
a1bd01d changing type[param] to return the state instead of the value
41b7fbd renaming oparse to filetype
98374bc renaming oparse to filetype
8ab03d0 renaming oparse to filetype
c2e83c5 renaming oparse to filetype
2360201 adding some comments
3904d2e fixing most of the function call stuff
13f16b6 the client is now successfully creating objects from the hashes passed by the server
6140bee making fact a real type
d94d7a3 moving state.rb to types/
e86cf4c renaming "value" to "is"
d8e8b7b renaming state, and adding modification class
c0c1f1a renaming attributes to states
6dce8fc renaming objects to types
a90af49 renaming objects to types
5e19d7d renaming objects to types
afd4349 updates
67fae6d updates
b4bb680 removing link when done
c6755f5 adding class collection and naming stuff
e5676ab testing keyword
f3d1118 removing some excess libs from blink.rb
585c4fc cleaning up the start script
61f8434 cleaning up a bit
52fe914 removing evaluate test
69651dd removing bogus output
8fd8d62 removing output, and fixing path so it is not hardcoded
9da1485 temporarily removing inclusion of time in output
4d7bbaa creating extra message methods
0187bf7 removing execute bit
6a82d07 adding readme
3824817 copy test script
67b7b34 okay, all tests pass again
35f742c adding client stuff to the library tree
02ed7d3 reorganizing tests
8bc935e adding comments
a0d0fa8 adding
11b0374 moving client.rb to the library tree
cb785bd moving client.rb to the library tree
8788552 fixing [] method in function.rb
c86a770 adding operatingsystemrelease
21ca565 renaming tc_functions.rb, and adding to ts_other.rb
1aab204 functions mostly work
c45c5c4 renaming
06734a9 updates so i can rename
9bf82b6 adding package source, initially including only files as a source
e40d5f2 returning value instead of fact
9fa899d reorganizing
4642515 reorganizing
5807dce reorganizing
6ee8b4e reorganizing
5416017 reorganizing
54e9b5e adding structure
diff --git a/acceptance/tests/allow_arbitrary_node_name_fact_for_agent.rb b/acceptance/tests/allow_arbitrary_node_name_fact_for_agent.rb
index 2e89d765f..c08c2e9a5 100644
--- a/acceptance/tests/allow_arbitrary_node_name_fact_for_agent.rb
+++ b/acceptance/tests/allow_arbitrary_node_name_fact_for_agent.rb
@@ -1,46 +1,48 @@
test_name "node_name_fact should be used to determine the node name for puppet agent"
success_message = "node_name_fact setting was correctly used to determine the node name"
node_names = []
on agents, facter('kernel') do
node_names << stdout.chomp
end
node_names.uniq!
authfile = "/tmp/auth.conf-2128-#{$$}"
authconf = node_names.map do |node_name|
%Q[
path /catalog/#{node_name}
auth yes
allow *
]
end.join("\n")
manifest_file = "/tmp/node_name_value-test-#{$$}.pp"
manifest = %Q[
Exec { path => "/usr/bin:/bin" }
node default {
exec { "false": }
}
]
manifest << node_names.map do |node_name|
%Q[
node "#{node_name}" {
exec { "echo #{success_message}": }
}
]
end.join("\n")
create_remote_file master, authfile, authconf
create_remote_file master, manifest_file, manifest
on master, "chmod 644 #{authfile} #{manifest_file}"
-with_master_running_on(master, "--rest_authconfig #{authfile} --manifest #{manifest_file} --daemonize --autosign true") do
+on hosts, "rm -rf /etc/puppet/ssl"
+
+with_master_running_on(master, "--rest_authconfig #{authfile} --manifest #{manifest_file} --daemonize --dns_alt_names=\"puppet, $(hostname -s), $(hostname -f)\" --autosign true") do
run_agent_on(agents, "--no-daemonize --verbose --onetime --node_name_fact kernel --server #{master}") do
assert_match(success_message, stdout)
end
end
diff --git a/acceptance/tests/allow_arbitrary_node_name_for_agent.rb b/acceptance/tests/allow_arbitrary_node_name_for_agent.rb
index f5e027660..f35c32bc3 100644
--- a/acceptance/tests/allow_arbitrary_node_name_for_agent.rb
+++ b/acceptance/tests/allow_arbitrary_node_name_for_agent.rb
@@ -1,29 +1,31 @@
test_name "node_name_value should be used as the node name for puppet agent"
success_message = "node_name_value setting was correctly used as the node name"
authfile = "/tmp/auth.conf-2128-#{$$}"
create_remote_file master, authfile, <<AUTHCONF
path /catalog/specified_node_name
auth yes
allow *
AUTHCONF
manifest_file = "/tmp/node_name_value-test-#{$$}.pp"
create_remote_file master, manifest_file, <<MANIFEST
Exec { path => "/usr/bin:/bin" }
node default {
exec { "false": }
}
node specified_node_name {
exec { "echo #{success_message}": }
}
MANIFEST
on master, "chmod 644 #{authfile} #{manifest_file}"
-with_master_running_on(master, "--rest_authconfig #{authfile} --manifest #{manifest_file} --daemonize --autosign true") do
+on hosts, "rm -rf /etc/puppet/ssl"
+
+with_master_running_on(master, "--rest_authconfig #{authfile} --manifest #{manifest_file} --daemonize --dns_alt_names=\"puppet, $(hostname -s), $(hostname -f)\" --autosign true") do
run_agent_on(agents, "--no-daemonize --verbose --onetime --node_name_value specified_node_name --server #{master}") do
assert_match(success_message, stdout)
end
end
diff --git a/acceptance/tests/resource/exec/accept_multi-line_commands.rb b/acceptance/tests/resource/exec/accept_multi-line_commands.rb
new file mode 100644
index 000000000..1e9aaf15f
--- /dev/null
+++ b/acceptance/tests/resource/exec/accept_multi-line_commands.rb
@@ -0,0 +1,24 @@
+test_name "Be able to execute multi-line commands (#9996)"
+
+temp_file_name = "/tmp/9996-multi-line-commands.#{$$}"
+test_manifest = <<HERE
+exec { "test exec":
+ command => "/bin/echo '#Test' > #{temp_file_name};
+ /bin/echo 'bob' >> #{temp_file_name};"
+}
+HERE
+
+expected_results = <<HERE
+#Test
+bob
+HERE
+
+on agents, "rm -f #{temp_file_name}"
+
+apply_manifest_on agents, test_manifest
+
+on(agents, "cat #{temp_file_name}").each do |result|
+ assert_equal(expected_results, "#{result.stdout}", "Unexpected result for host '#{result.host}'")
+end
+
+on agents, "rm -f #{temp_file_name}"
diff --git a/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb b/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb
index f774eca05..347b5991f 100644
--- a/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb
+++ b/acceptance/tests/ticket_5477_master_not_dectect_sitepp.rb
@@ -1,33 +1,34 @@
# In 2.6, compile does not fail when site.pp does not exist.
#
# However, if a catalog is compiled when site.pp does not exist,
# puppetmaster does not detect when site.pp is created. This requires a restart
#
test_name "Ticket 5477, Puppet Master does not detect newly created site.pp file"
manifest_file = "/tmp/missing_site-5477-#{$$}.pp"
on master, "rm -f #{manifest_file}"
+on hosts, "rm -rf /etc/puppet/ssl"
-with_master_running_on(master, "--manifest #{manifest_file} --certdnsnames=\"puppet:$(hostname -s):$(hostname -f)\" --verbose --filetimeout 1") do
+with_master_running_on(master, "--manifest #{manifest_file} --dns_alt_names=\"puppet, $(hostname -s), $(hostname -f)\" --verbose --filetimeout 1 --autosign true") do
# Run test on Agents
step "Agent: agent --test"
on agents, puppet_agent("--test --server #{master}")
# Create a new site.pp
step "Master: create basic site.pp file"
create_remote_file master, manifest_file, "notify{ticket_5477_notify:}"
on master, "chmod 644 #{manifest_file}"
sleep 3
step "Agent: puppet agent --test"
agents.each do |host|
on(host, puppet_agent("--test --server #{master}"), :acceptable_exit_codes => [2]) do
assert_match(/ticket_5477_notify/, stdout, "#{host}: Site.pp not detected on Puppet Master")
end
end
end
diff --git a/acceptance/tests/ticket_7117_broke_env_criteria_authconf.rb b/acceptance/tests/ticket_7117_broke_env_criteria_authconf.rb
index 5eeb2f749..eda6ae3de 100644
--- a/acceptance/tests/ticket_7117_broke_env_criteria_authconf.rb
+++ b/acceptance/tests/ticket_7117_broke_env_criteria_authconf.rb
@@ -1,27 +1,29 @@
test_name "#7117 Broke the environment criteria in auth.conf"
# add to auth.conf
add_2_authconf = %q{
path /
environment override
auth any
allow *
}
step "Create a temp auth.conf"
create_remote_file master, "/tmp/auth.conf-7117", add_2_authconf
on master, "chmod 644 /tmp/auth.conf-7117"
-with_master_running_on(master, "--certdnsnames=\"puppet:$(hostname -s):$(hostname -f)\" --rest_authconfig /tmp/auth.conf-7117 --verbose --autosign true") do
+on hosts, "rm -rf /etc/puppet/ssl"
+
+with_master_running_on(master, "--dns_alt_names=\"puppet, $(hostname -s), $(hostname -f)\" --rest_authconfig /tmp/auth.conf-7117 --verbose --autosign true") do
# Run test on Agents
step "Run agent to upload facts"
on agents, puppet_agent("--test --server #{master}")
step "Fetch agent facts from Puppet Master"
agents.each do |host|
on(host, "curl -k -H \"Accept: yaml\" https://#{master}:8140/override/facts/\`hostname -f\`") do
assert_match(/--- !ruby\/object:Puppet::Node::Facts/, stdout, "Agent Facts not returned for #{host}")
end
end
end
diff --git a/conf/redhat/puppet.spec b/conf/redhat/puppet.spec
index b0e29ebfc..e6206a195 100644
--- a/conf/redhat/puppet.spec
+++ b/conf/redhat/puppet.spec
@@ -1,570 +1,576 @@
# Augeas and SELinux requirements may be disabled at build time by passing
# --without augeas and/or --without selinux to rpmbuild or mock
%{!?ruby_sitelibdir: %global ruby_sitelibdir %(ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"]')}
%global confdir conf/redhat
Name: puppet
Version: 2.7.6
-Release: 0.1%{?dist}
+Release: 1%{?dist}
Summary: A network tool for managing many disparate systems
License: ASL 2.0
URL: http://puppetlabs.com
-Source0: http://puppetlabs.com/downloads/%{name}/%{name}-%{version}rc2.tar.gz
-Source1: http://puppetlabs.com/downloads/%{name}/%{name}-%{version}rc2.tar.gz.asc
+Source0: http://puppetlabs.com/downloads/%{name}/%{name}-%{version}.tar.gz
+Source1: http://puppetlabs.com/downloads/%{name}/%{name}-%{version}.tar.gz.asc
Group: System Environment/Base
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: facter >= 1.5
BuildRequires: ruby >= 1.8.1
%if 0%{?fedora} || 0%{?rhel} >= 5
BuildArch: noarch
Requires: ruby(abi) = 1.8
Requires: ruby-shadow
%endif
# Pull in ruby selinux bindings where available
%if 0%{?fedora} || 0%{?rhel} >= 6
%{!?_without_selinux:Requires: ruby(selinux), libselinux-utils}
%else
%if 0%{?rhel} && 0%{?rhel} == 5
%{!?_without_selinux:Requires: libselinux-ruby, libselinux-utils}
%endif
%endif
Requires: facter >= 1.5
Requires: ruby >= 1.8.1
%{!?_without_augeas:Requires: ruby-augeas}
Requires(pre): shadow-utils
Requires(post): chkconfig
Requires(preun): chkconfig
Requires(preun): initscripts
Requires(postun): initscripts
%description
Puppet lets you centrally manage every important aspect of your system using a
cross-platform specification language that manages all the separate elements
normally aggregated in different files, like users, cron jobs, and hosts,
along with obviously discrete elements like packages, services, and files.
%package server
Group: System Environment/Base
Summary: Server for the puppet system management tool
Requires: puppet = %{version}-%{release}
Requires(post): chkconfig
Requires(preun): chkconfig
Requires(preun): initscripts
Requires(postun): initscripts
%description server
Provides the central puppet server daemon which provides manifests to clients.
The server can also function as a certificate authority and file server.
%prep
-%setup -q -n %{name}-%{version}rc2
+%setup -q -n %{name}-%{version}
patch -s -p1 < conf/redhat/rundir-perms.patch
%build
# Fix some rpmlint complaints
for f in mac_dscl.pp mac_dscl_revert.pp \
mac_pkgdmg.pp ; do
sed -i -e'1d' examples/$f
chmod a-x examples/$f
done
for f in external/nagios.rb network/http_server/mongrel.rb relationship.rb; do
sed -i -e '1d' lib/puppet/$f
done
chmod +x ext/puppetstoredconfigclean.rb
find examples/ -type f -empty | xargs rm
find examples/ -type f | xargs chmod a-x
# puppet-queue.conf is more of an example, used for stompserver
mv conf/puppet-queue.conf examples/etc/puppet/
%install
rm -rf %{buildroot}
ruby install.rb --destdir=%{buildroot} --quick --no-rdoc
install -d -m0755 %{buildroot}%{_sysconfdir}/puppet/manifests
install -d -m0755 %{buildroot}%{_datadir}/%{name}/modules
install -d -m0755 %{buildroot}%{_localstatedir}/lib/puppet
install -d -m0755 %{buildroot}%{_localstatedir}/run/puppet
install -d -m0750 %{buildroot}%{_localstatedir}/log/puppet
install -Dp -m0644 %{confdir}/client.sysconfig %{buildroot}%{_sysconfdir}/sysconfig/puppet
install -Dp -m0755 %{confdir}/client.init %{buildroot}%{_initrddir}/puppet
install -Dp -m0644 %{confdir}/server.sysconfig %{buildroot}%{_sysconfdir}/sysconfig/puppetmaster
install -Dp -m0755 %{confdir}/server.init %{buildroot}%{_initrddir}/puppetmaster
install -Dp -m0644 %{confdir}/fileserver.conf %{buildroot}%{_sysconfdir}/puppet/fileserver.conf
install -Dp -m0644 %{confdir}/puppet.conf %{buildroot}%{_sysconfdir}/puppet/puppet.conf
install -Dp -m0644 %{confdir}/logrotate %{buildroot}%{_sysconfdir}/logrotate.d/puppet
# We need something for these ghosted files, otherwise rpmbuild
# will complain loudly. They won't be included in the binary packages
touch %{buildroot}%{_sysconfdir}/puppet/puppetmasterd.conf
touch %{buildroot}%{_sysconfdir}/puppet/puppetca.conf
touch %{buildroot}%{_sysconfdir}/puppet/puppetd.conf
# Install the ext/ directory to %%{_datadir}/%%{name}
install -d %{buildroot}%{_datadir}/%{name}
cp -a ext/ %{buildroot}%{_datadir}/%{name}
# emacs and vim bits are installed elsewhere
rm -rf %{buildroot}%{_datadir}/%{name}/ext/{emacs,vim}
# Install emacs mode files
emacsdir=%{buildroot}%{_datadir}/emacs/site-lisp
install -Dp -m0644 ext/emacs/puppet-mode.el $emacsdir/puppet-mode.el
install -Dp -m0644 ext/emacs/puppet-mode-init.el \
$emacsdir/site-start.d/puppet-mode-init.el
# Install vim syntax files
vimdir=%{buildroot}%{_datadir}/vim/vimfiles
install -Dp -m0644 ext/vim/ftdetect/puppet.vim $vimdir/ftdetect/puppet.vim
install -Dp -m0644 ext/vim/syntax/puppet.vim $vimdir/syntax/puppet.vim
%if 0%{?fedora} >= 15
# Setup tmpfiles.d config
mkdir -p %{buildroot}%{_sysconfdir}/tmpfiles.d
echo "D /var/run/%{name} 0755 %{name} %{name} -" > \
%{buildroot}%{_sysconfdir}/tmpfiles.d/%{name}.conf
%endif
%files
%defattr(-, root, root, 0755)
%doc CHANGELOG LICENSE README.md examples
%{_bindir}/pi
%{_bindir}/puppet
%{_bindir}/ralsh
%{_bindir}/filebucket
%{_bindir}/puppetdoc
%{_sbindir}/puppetca
%{_sbindir}/puppetd
%{ruby_sitelibdir}/*
%{_initrddir}/puppet
%dir %{_sysconfdir}/puppet
%if 0%{?fedora} >= 15
%config(noreplace) %{_sysconfdir}/tmpfiles.d/%{name}.conf
%endif
%config(noreplace) %{_sysconfdir}/sysconfig/puppet
%config(noreplace) %{_sysconfdir}/puppet/puppet.conf
%config(noreplace) %{_sysconfdir}/puppet/auth.conf
%ghost %config(noreplace,missingok) %{_sysconfdir}/puppet/puppetca.conf
%ghost %config(noreplace,missingok) %{_sysconfdir}/puppet/puppetd.conf
%config(noreplace) %{_sysconfdir}/logrotate.d/puppet
# We don't want to require emacs or vim, so we need to own these dirs
%{_datadir}/emacs
%{_datadir}/vim
%{_datadir}/%{name}
# These need to be owned by puppet so the server can
# write to them
%attr(-, puppet, puppet) %{_localstatedir}/run/puppet
%attr(-, puppet, puppet) %{_localstatedir}/log/puppet
%attr(-, puppet, puppet) %{_localstatedir}/lib/puppet
%{_mandir}/man5/puppet.conf.5.gz
%{_mandir}/man8/pi.8.gz
%{_mandir}/man8/puppet.8.gz
%{_mandir}/man8/puppetca.8.gz
%{_mandir}/man8/puppetd.8.gz
%{_mandir}/man8/ralsh.8.gz
%{_mandir}/man8/puppetdoc.8.gz
%{_mandir}/man8/puppet-agent.8.gz
%{_mandir}/man8/puppet-apply.8.gz
%{_mandir}/man8/puppet-catalog.8.gz
%{_mandir}/man8/puppet-describe.8.gz
%{_mandir}/man8/puppet-cert.8.gz
%{_mandir}/man8/puppet-certificate.8.gz
%{_mandir}/man8/puppet-certificate_request.8.gz
%{_mandir}/man8/puppet-certificate_revocation_list.8.gz
%{_mandir}/man8/puppet-config.8.gz
%{_mandir}/man8/puppet-device.8.gz
%{_mandir}/man8/puppet-doc.8.gz
%{_mandir}/man8/puppet-facts.8.gz
%{_mandir}/man8/puppet-file.8.gz
%{_mandir}/man8/puppet-filebucket.8.gz
%{_mandir}/man8/puppet-help.8.gz
%{_mandir}/man8/puppet-inspect.8.gz
%{_mandir}/man8/puppet-key.8.gz
%{_mandir}/man8/puppet-kick.8.gz
%{_mandir}/man8/puppet-man.8.gz
%{_mandir}/man8/puppet-node.8.gz
%{_mandir}/man8/puppet-parser.8.gz
%{_mandir}/man8/puppet-plugin.8.gz
%{_mandir}/man8/puppet-queue.8.gz
%{_mandir}/man8/puppet-report.8.gz
%{_mandir}/man8/puppet-resource.8.gz
%{_mandir}/man8/puppet-resource_type.8.gz
%{_mandir}/man8/puppet-secret_agent.8.gz
%{_mandir}/man8/puppet-status.8.gz
%files server
%defattr(-, root, root, 0755)
%{_sbindir}/puppetmasterd
%{_sbindir}/puppetrun
%{_sbindir}/puppetqd
%{_initrddir}/puppetmaster
%config(noreplace) %{_sysconfdir}/puppet/fileserver.conf
%dir %{_sysconfdir}/puppet/manifests
%config(noreplace) %{_sysconfdir}/sysconfig/puppetmaster
%ghost %config(noreplace,missingok) %{_sysconfdir}/puppet/puppetmasterd.conf
%{_mandir}/man8/filebucket.8.gz
%{_mandir}/man8/puppetmasterd.8.gz
%{_mandir}/man8/puppetrun.8.gz
%{_mandir}/man8/puppetqd.8.gz
%{_mandir}/man8/puppet-master.8.gz
# Fixed uid/gid were assigned in bz 472073 (Fedora), 471918 (RHEL-5),
# and 471919 (RHEL-4)
%pre
getent group puppet &>/dev/null || groupadd -r puppet -g 52 &>/dev/null
getent passwd puppet &>/dev/null || \
useradd -r -u 52 -g puppet -d %{_localstatedir}/lib/puppet -s /sbin/nologin \
-c "Puppet" puppet &>/dev/null
# ensure that old setups have the right puppet home dir
if [ $1 -gt 1 ] ; then
usermod -d %{_localstatedir}/lib/puppet puppet &>/dev/null
fi
exit 0
%post
/sbin/chkconfig --add puppet || :
if [ "$1" -ge 1 ]; then
# The pidfile changed from 0.25.x to 2.6.x, handle upgrades without leaving
# the old process running.
oldpid="%{_localstatedir}/run/puppet/puppetd.pid"
newpid="%{_localstatedir}/run/puppet/agent.pid"
if [ -s "$oldpid" -a ! -s "$newpid" ]; then
(kill $(< "$oldpid") && rm -f "$oldpid" && \
/sbin/service puppet start) >/dev/null 2>&1 || :
fi
fi
%post server
/sbin/chkconfig --add puppetmaster || :
if [ "$1" -ge 1 ]; then
# The pidfile changed from 0.25.x to 2.6.x, handle upgrades without leaving
# the old process running.
oldpid="%{_localstatedir}/run/puppet/puppetmasterd.pid"
newpid="%{_localstatedir}/run/puppet/master.pid"
if [ -s "$oldpid" -a ! -s "$newpid" ]; then
(kill $(< "$oldpid") && rm -f "$oldpid" && \
/sbin/service puppetmaster start) >/dev/null 2>&1 || :
fi
fi
%preun
if [ "$1" = 0 ] ; then
/sbin/service puppet stop >/dev/null 2>&1
/sbin/chkconfig --del puppet || :
fi
%preun server
if [ "$1" = 0 ] ; then
/sbin/service puppetmaster stop >/dev/null 2>&1
/sbin/chkconfig --del puppetmaster || :
fi
%postun
if [ "$1" -ge 1 ]; then
/sbin/service puppet condrestart >/dev/null 2>&1 || :
fi
%postun server
if [ "$1" -ge 1 ]; then
/sbin/service puppetmaster condrestart >/dev/null 2>&1 || :
fi
%clean
rm -rf %{buildroot}
%changelog
+* Fri Oct 21 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.6-1
+- 2.7.6 final
+
+* Thu Oct 13 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.6-.1rc3
+- New RC
+
* Fri Oct 07 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.6-0.1rc2
- New RC
* Mon Oct 03 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.6-0.1rc1
- New RC
* Fri Sep 30 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.5-1
- Fixes for CVE-2011-3869, 3870, 3871
* Wed Sep 28 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.4-1
- Fix for CVE-2011-3484
* Wed Jul 06 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.2-0.2.rc1
- Clean up rpmlint errors
- Put man pages in correct package
* Wed Jul 06 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.7.2-0.1.rc1
- Update to 2.7.2rc1
* Wed Jun 15 2011 Todd Zullinger <tmz@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
* Tue Jun 14 2011 Michael Stahnke <stahnma@puppetlabs.com> - 2.6.9rc1-1
- Update to 2.6.9rc1
* Thu Apr 14 2011 Todd Zullinger <tmz@pobox.com> - 2.6.8-1
- Update to 2.6.8
* Thu Mar 24 2011 Todd Zullinger <tmz@pobox.com> - 2.6.7-1
- Update to 2.6.7
* Wed Mar 16 2011 Todd Zullinger <tmz@pobox.com> - 2.6.6-1
- Update to 2.6.6
- Ensure %%pre exits cleanly
- Fix License tag, puppet is now GPLv2 only
- Create and own /usr/share/puppet/modules (#615432)
- Properly restart puppet agent/master daemons on upgrades from 0.25.x
- Require libselinux-utils when selinux support is enabled
- Support tmpfiles.d for Fedora >= 15 (#656677)
* Wed Feb 09 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 0.25.5-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
* Mon May 17 2010 Todd Zullinger <tmz@pobox.com> - 0.25.5-1
- Update to 0.25.5
- Adjust selinux conditional for EL-6
- Apply rundir-perms patch from tarball rather than including it separately
- Update URL's to reflect the new puppetlabs.com domain
* Fri Jan 29 2010 Todd Zullinger <tmz@pobox.com> - 0.25.4-1
- Update to 0.25.4
* Tue Jan 19 2010 Todd Zullinger <tmz@pobox.com> - 0.25.3-2
- Apply upstream patch to fix cron resources (upstream #2845)
* Mon Jan 11 2010 Todd Zullinger <tmz@pobox.com> - 0.25.3-1
- Update to 0.25.3
* Tue Jan 05 2010 Todd Zullinger <tmz@pobox.com> - 0.25.2-1.1
- Replace %%define with %%global for macros
* Tue Jan 05 2010 Todd Zullinger <tmz@pobox.com> - 0.25.2-1
- Update to 0.25.2
- Fixes CVE-2010-0156, tmpfile security issue (#502881)
- Install auth.conf, puppetqd manpage, and queuing examples/docs
* Wed Nov 25 2009 Jeroen van Meeuwen <j.van.meeuwen@ogd.nl> - 0.25.1-1
- New upstream version
* Tue Oct 27 2009 Todd Zullinger <tmz@pobox.com> - 0.25.1-0.3
- Update to 0.25.1
- Include the pi program and man page (R.I.Pienaar)
* Sat Oct 17 2009 Todd Zullinger <tmz@pobox.com> - 0.25.1-0.2.rc2
- Update to 0.25.1rc2
* Tue Sep 22 2009 Todd Zullinger <tmz@pobox.com> - 0.25.1-0.1.rc1
- Update to 0.25.1rc1
- Move puppetca to puppet package, it has uses on client systems
- Drop redundant %%doc from manpage %%file listings
* Fri Sep 04 2009 Todd Zullinger <tmz@pobox.com> - 0.25.0-1
- Update to 0.25.0
- Fix permissions on /var/log/puppet (#495096)
- Install emacs mode and vim syntax files (#491437)
- Install ext/ directory in %%{_datadir}/%%{name} (/usr/share/puppet)
* Mon May 04 2009 Todd Zullinger <tmz@pobox.com> - 0.25.0-0.1.beta1
- Update to 0.25.0beta1
- Make Augeas and SELinux requirements build time options
* Mon Mar 23 2009 Todd Zullinger <tmz@pobox.com> - 0.24.8-1
- Update to 0.24.8
- Quiet output from %%pre
- Use upstream install script
- Increase required facter version to >= 1.5
* Tue Dec 16 2008 Todd Zullinger <tmz@pobox.com> - 0.24.7-4
- Remove redundant useradd from %%pre
* Tue Dec 16 2008 Jeroen van Meeuwen <kanarip@kanarip.com> - 0.24.7-3
- New upstream version
- Set a static uid and gid (#472073, #471918, #471919)
- Add a conditional requirement on libselinux-ruby for Fedora >= 9
- Add a dependency on ruby-augeas
* Wed Oct 22 2008 Todd Zullinger <tmz@pobox.com> - 0.24.6-1
- Update to 0.24.6
- Require ruby-shadow on Fedora and RHEL >= 5
- Simplify Fedora/RHEL version checks for ruby(abi) and BuildArch
- Require chkconfig and initstripts for preun, post, and postun scripts
- Conditionally restart puppet in %%postun
- Ensure %%preun, %%post, and %%postun scripts exit cleanly
- Create puppet user/group according to Fedora packaging guidelines
- Quiet a few rpmlint complaints
- Remove useless %%pbuild macro
- Make specfile more like the Fedora/EPEL template
* Mon Jul 28 2008 David Lutterkort <dlutter@redhat.com> - 0.24.5-1
- Add /usr/bin/puppetdoc
* Thu Jul 24 2008 Brenton Leanhardt <bleanhar@redhat.com>
- New version
- man pages now ship with tarball
- examples/code moved to root examples dir in upstream tarball
* Tue Mar 25 2008 David Lutterkort <dlutter@redhat.com> - 0.24.4-1
- Add man pages (from separate tarball, upstream will fix to
include in main tarball)
* Mon Mar 24 2008 David Lutterkort <dlutter@redhat.com> - 0.24.3-1
- New version
* Wed Mar 5 2008 David Lutterkort <dlutter@redhat.com> - 0.24.2-1
- New version
* Sat Dec 22 2007 David Lutterkort <dlutter@redhat.com> - 0.24.1-1
- New version
* Mon Dec 17 2007 David Lutterkort <dlutter@redhat.com> - 0.24.0-2
- Use updated upstream tarball that contains yumhelper.py
* Fri Dec 14 2007 David Lutterkort <dlutter@redhat.com> - 0.24.0-1
- Fixed license
- Munge examples/ to make rpmlint happier
* Wed Aug 22 2007 David Lutterkort <dlutter@redhat.com> - 0.23.2-1
- New version
* Thu Jul 26 2007 David Lutterkort <dlutter@redhat.com> - 0.23.1-1
- Remove old config files
* Wed Jun 20 2007 David Lutterkort <dlutter@redhat.com> - 0.23.0-1
- Install one puppet.conf instead of old config files, keep old configs
around to ease update
- Use plain shell commands in install instead of macros
* Wed May 2 2007 David Lutterkort <dlutter@redhat.com> - 0.22.4-1
- New version
* Thu Mar 29 2007 David Lutterkort <dlutter@redhat.com> - 0.22.3-1
- Claim ownership of _sysconfdir/puppet (bz 233908)
* Mon Mar 19 2007 David Lutterkort <dlutter@redhat.com> - 0.22.2-1
- Set puppet's homedir to /var/lib/puppet, not /var/puppet
- Remove no-lockdir patch, not needed anymore
* Mon Feb 12 2007 David Lutterkort <dlutter@redhat.com> - 0.22.1-2
- Fix bogus config parameter in puppetd.conf
* Sat Feb 3 2007 David Lutterkort <dlutter@redhat.com> - 0.22.1-1
- New version
* Fri Jan 5 2007 David Lutterkort <dlutter@redhat.com> - 0.22.0-1
- New version
* Mon Nov 20 2006 David Lutterkort <dlutter@redhat.com> - 0.20.1-2
- Make require ruby(abi) and buildarch: noarch conditional for fedora 5 or
later to allow building on older fedora releases
* Mon Nov 13 2006 David Lutterkort <dlutter@redhat.com> - 0.20.1-1
- New version
* Mon Oct 23 2006 David Lutterkort <dlutter@redhat.com> - 0.20.0-1
- New version
* Tue Sep 26 2006 David Lutterkort <dlutter@redhat.com> - 0.19.3-1
- New version
* Mon Sep 18 2006 David Lutterkort <dlutter@redhat.com> - 0.19.1-1
- New version
* Thu Sep 7 2006 David Lutterkort <dlutter@redhat.com> - 0.19.0-1
- New version
* Tue Aug 1 2006 David Lutterkort <dlutter@redhat.com> - 0.18.4-2
- Use /usr/bin/ruby directly instead of /usr/bin/env ruby in
executables. Otherwise, initscripts break since pidof can't find the
right process
* Tue Aug 1 2006 David Lutterkort <dlutter@redhat.com> - 0.18.4-1
- New version
* Fri Jul 14 2006 David Lutterkort <dlutter@redhat.com> - 0.18.3-1
- New version
* Wed Jul 5 2006 David Lutterkort <dlutter@redhat.com> - 0.18.2-1
- New version
* Wed Jun 28 2006 David Lutterkort <dlutter@redhat.com> - 0.18.1-1
- Removed lsb-config.patch and yumrepo.patch since they are upstream now
* Mon Jun 19 2006 David Lutterkort <dlutter@redhat.com> - 0.18.0-1
- Patch config for LSB compliance (lsb-config.patch)
- Changed config moves /var/puppet to /var/lib/puppet, /etc/puppet/ssl
to /var/lib/puppet, /etc/puppet/clases.txt to /var/lib/puppet/classes.txt,
/etc/puppet/localconfig.yaml to /var/lib/puppet/localconfig.yaml
* Fri May 19 2006 David Lutterkort <dlutter@redhat.com> - 0.17.2-1
- Added /usr/bin/puppetrun to server subpackage
- Backported patch for yumrepo type (yumrepo.patch)
* Wed May 3 2006 David Lutterkort <dlutter@redhat.com> - 0.16.4-1
- Rebuilt
* Fri Apr 21 2006 David Lutterkort <dlutter@redhat.com> - 0.16.0-1
- Fix default file permissions in server subpackage
- Run puppetmaster as user puppet
- rebuilt for 0.16.0
* Mon Apr 17 2006 David Lutterkort <dlutter@redhat.com> - 0.15.3-2
- Don't create empty log files in post-install scriptlet
* Fri Apr 7 2006 David Lutterkort <dlutter@redhat.com> - 0.15.3-1
- Rebuilt for new version
* Wed Mar 22 2006 David Lutterkort <dlutter@redhat.com> - 0.15.1-1
- Patch0: Run puppetmaster as root; running as puppet is not ready
for primetime
* Mon Mar 13 2006 David Lutterkort <dlutter@redhat.com> - 0.15.0-1
- Commented out noarch; requires fix for bz184199
* Mon Mar 6 2006 David Lutterkort <dlutter@redhat.com> - 0.14.0-1
- Added BuildRequires for ruby
* Wed Mar 1 2006 David Lutterkort <dlutter@redhat.com> - 0.13.5-1
- Removed use of fedora-usermgmt. It is not required for Fedora Extras and
makes it unnecessarily hard to use this rpm outside of Fedora. Just
allocate the puppet uid/gid dynamically
* Sun Feb 19 2006 David Lutterkort <dlutter@redhat.com> - 0.13.0-4
- Use fedora-usermgmt to create puppet user/group. Use uid/gid 24. Fixed
problem with listing fileserver.conf and puppetmaster.conf twice
* Wed Feb 8 2006 David Lutterkort <dlutter@redhat.com> - 0.13.0-3
- Fix puppetd.conf
* Wed Feb 8 2006 David Lutterkort <dlutter@redhat.com> - 0.13.0-2
- Changes to run puppetmaster as user puppet
* Mon Feb 6 2006 David Lutterkort <dlutter@redhat.com> - 0.13.0-1
- Don't mark initscripts as config files
* Mon Feb 6 2006 David Lutterkort <dlutter@redhat.com> - 0.12.0-2
- Fix BuildRoot. Add dist to release
* Tue Jan 17 2006 David Lutterkort <dlutter@redhat.com> - 0.11.0-1
- Rebuild
* Thu Jan 12 2006 David Lutterkort <dlutter@redhat.com> - 0.10.2-1
- Updated for 0.10.2 Fixed minor kink in how Source is given
* Wed Jan 11 2006 David Lutterkort <dlutter@redhat.com> - 0.10.1-3
- Added basic fileserver.conf
* Wed Jan 11 2006 David Lutterkort <dlutter@redhat.com> - 0.10.1-1
- Updated. Moved installation of library files to sitelibdir. Pulled
initscripts into separate files. Folded tools rpm into server
* Thu Nov 24 2005 Duane Griffin <d.griffin@psenterprise.com>
- Added init scripts for the client
* Wed Nov 23 2005 Duane Griffin <d.griffin@psenterprise.com>
- First packaging
diff --git a/lib/puppet/application/cert.rb b/lib/puppet/application/cert.rb
index 330fba8bd..7285d8869 100644
--- a/lib/puppet/application/cert.rb
+++ b/lib/puppet/application/cert.rb
@@ -1,227 +1,241 @@
require 'puppet/application'
class Puppet::Application::Cert < Puppet::Application
should_parse_config
run_mode :master
attr_accessor :all, :ca, :digest, :signed
def subcommand
@subcommand
end
+
def subcommand=(name)
# Handle the nasty, legacy mapping of "clean" to "destroy".
sub = name.to_sym
@subcommand = (sub == :clean ? :destroy : sub)
end
option("--clean", "-c") do
self.subcommand = "destroy"
end
option("--all", "-a") do
@all = true
end
option("--digest DIGEST") do |arg|
@digest = arg
end
option("--signed", "-s") do
@signed = true
end
option("--debug", "-d") do |arg|
Puppet::Util::Log.level = :debug
end
require 'puppet/ssl/certificate_authority/interface'
Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject {|m| m == :destroy }.each do |method|
- option("--#{method}", "-#{method.to_s[0,1]}") do
+ option("--#{method.to_s.gsub('_','-')}", "-#{method.to_s[0,1]}") do
self.subcommand = method
end
end
+ option("--[no-]allow-dns-alt-names") do |value|
+ options[:allow_dns_alt_names] = value
+ end
+
option("--verbose", "-v") do
Puppet::Util::Log.level = :info
end
def help
<<-HELP
puppet-cert(8) -- Manage certificates and requests
========
SYNOPSIS
--------
Standalone certificate authority. Capable of generating certificates,
but mostly used for signing certificate requests from puppet clients.
USAGE
-----
puppet cert <action> [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose]
[--digest <digest>] [<host>]
DESCRIPTION
-----------
Because the puppet master service defaults to not signing client
certificate requests, this script is available for signing outstanding
requests. It can be used to list outstanding requests and then either
sign them individually or sign all of them.
ACTIONS
-------
Every action except 'list' and 'generate' requires a hostname to act on,
unless the '--all' option is set.
* clean:
Revoke a host's certificate (if applicable) and remove all files
related to that host from puppet cert's storage. This is useful when
rebuilding hosts, since new certificate signing requests will only be
honored if puppet cert does not have a copy of a signed certificate
for that host. If '--all' is specified then all host certificates,
both signed and unsigned, will be removed.
* fingerprint:
Print the DIGEST (defaults to md5) fingerprint of a host's
certificate.
* generate:
Generate a certificate for a named client. A certificate/keypair will
be generated for each client named on the command line.
* list:
List outstanding certificate requests. If '--all' is specified, signed
certificates are also listed, prefixed by '+', and revoked or invalid
certificates are prefixed by '-' (the verification outcome is printed
in parenthesis).
* print:
Print the full-text version of a host's certificate.
* revoke:
Revoke the certificate of a client. The certificate can be specified
either by its serial number (given as a decimal number or a
hexadecimal number prefixed by '0x') or by its hostname. The
certificate is revoked by adding it to the Certificate Revocation List
given by the 'cacrl' configuration option. Note that the puppet master
needs to be restarted after revoking certificates.
* sign:
Sign an outstanding certificate request.
* verify:
Verify the named certificate against the local CA certificate.
OPTIONS
-------
Note that any configuration parameter that's valid in the configuration
file is also a valid long argument. For example, 'ssldir' is a valid
configuration parameter, so you can specify '--ssldir <directory>' as an
argument.
See the configuration file documentation at
http://docs.puppetlabs.com/references/stable/configuration.html for the
full list of acceptable parameters. A commented list of all
configuration options can also be generated by running puppet cert with
'--genconfig'.
* --all:
Operate on all items. Currently only makes sense with the 'sign',
'clean', 'list', and 'fingerprint' actions.
* --digest:
Set the digest for fingerprinting (defaults to md5). Valid values
depends on your openssl and openssl ruby extension version, but should
contain at least md5, sha1, md2, sha256.
* --debug:
Enable full debugging.
* --help:
Print this help message
* --verbose:
Enable verbosity.
* --version:
Print the puppet version number and exit.
EXAMPLE
-------
$ puppet cert list
culain.madstop.com
$ puppet cert sign culain.madstop.com
AUTHOR
------
Luke Kanies
COPYRIGHT
---------
Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
HELP
end
def main
if @all
hosts = :all
elsif @signed
hosts = :signed
else
hosts = command_line.args.collect { |h| h.downcase }
end
begin
- @ca.apply(:revoke, :to => hosts) if subcommand == :destroy
- @ca.apply(subcommand, :to => hosts, :digest => @digest)
+ @ca.apply(:revoke, options.merge(:to => hosts)) if subcommand == :destroy
+ @ca.apply(subcommand, options.merge(:to => hosts, :digest => @digest))
rescue => detail
puts detail.backtrace if Puppet[:trace]
puts detail.to_s
exit(24)
end
end
def setup
require 'puppet/ssl/certificate_authority'
exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
Puppet::Util::Log.newdestination :console
if [:generate, :destroy].include? subcommand
Puppet::SSL::Host.ca_location = :local
else
Puppet::SSL::Host.ca_location = :only
end
+ # If we are generating, and the option came from the CLI, it gets added to
+ # the data. This will do the right thing for non-local certificates, in
+ # that the command line but *NOT* the config file option will apply.
+ if subcommand == :generate
+ if Puppet.settings.setting(:dns_alt_names).setbycli
+ options[:dns_alt_names] = Puppet[:dns_alt_names]
+ end
+ end
+
begin
@ca = Puppet::SSL::CertificateAuthority.new
rescue => detail
puts detail.backtrace if Puppet[:trace]
puts detail.to_s
exit(23)
end
end
def parse_options
# handle the bareword subcommand pattern.
result = super
unless self.subcommand then
if sub = self.command_line.args.shift then
self.subcommand = sub
else
puts help
exit
end
end
result
end
end
diff --git a/lib/puppet/application/kick.rb b/lib/puppet/application/kick.rb
index 4f3ed1802..72f0608f6 100644
--- a/lib/puppet/application/kick.rb
+++ b/lib/puppet/application/kick.rb
@@ -1,337 +1,335 @@
require 'puppet/application'
class Puppet::Application::Kick < Puppet::Application
should_not_parse_config
attr_accessor :hosts, :tags, :classes
option("--all","-a")
option("--foreground","-f")
option("--debug","-d")
option("--ping","-P")
option("--test")
option("--host HOST") do |arg|
@hosts << arg
end
option("--tag TAG", "-t") do |arg|
@tags << arg
end
option("--class CLASS", "-c") do |arg|
@classes << arg
end
option("--no-fqdn", "-n") do |arg|
options[:fqdn] = false
end
option("--parallel PARALLEL", "-p") do |arg|
begin
options[:parallel] = Integer(arg)
rescue
$stderr.puts "Could not convert #{arg.inspect} to an integer"
exit(23)
end
end
def help
<<-HELP
puppet-kick(8) -- Remotely control puppet agent
========
SYNOPSIS
--------
Trigger a puppet agent run on a set of hosts.
USAGE
-----
puppet kick [-a|--all] [-c|--class <class>] [-d|--debug] [-f|--foreground]
[-h|--help] [--host <host>] [--no-fqdn] [--ignoreschedules]
[-t|--tag <tag>] [--test] [-p|--ping] <host> [<host> [...]]
DESCRIPTION
-----------
This script can be used to connect to a set of machines running 'puppet
agent' and trigger them to run their configurations. The most common
usage would be to specify a class of hosts and a set of tags, and
'puppet kick' would look up in LDAP all of the hosts matching that
class, then connect to each host and trigger a run of all of the objects
with the specified tags.
If you are not storing your host configurations in LDAP, you can specify
hosts manually.
You will most likely have to run 'puppet kick' as root to get access to
the SSL certificates.
'puppet kick' reads 'puppet master''s configuration file, so that it can
copy things like LDAP settings.
USAGE NOTES
-----------
Puppet kick is useless unless puppet agent is listening for incoming
connections and allowing access to the `run` endpoint. This entails
starting the agent with `listen = true` in its puppet.conf file, and
allowing access to the `/run` path in its auth.conf file; see
`http://docs.puppetlabs.com/guides/rest_auth_conf.html` for more
details.
Additionally, due to a known bug, you must make sure a
namespaceauth.conf file exists in puppet agent's $confdir. This file
will not be consulted, and may be left empty.
OPTIONS
-------
Note that any configuration parameter that's valid in the configuration
file is also a valid long argument. For example, 'ssldir' is a valid
configuration parameter, so you can specify '--ssldir <directory>' as an
argument.
See the configuration file documentation at
http://docs.puppetlabs.com/references/latest/configuration.html for
the full list of acceptable parameters. A commented list of all
configuration options can also be generated by running puppet master
with '--genconfig'.
* --all:
Connect to all available hosts. Requires LDAP support at this point.
* --class:
Specify a class of machines to which to connect. This only works if
you have LDAP configured, at the moment.
* --debug:
Enable full debugging.
* --foreground:
Run each configuration in the foreground; that is, when connecting to
a host, do not return until the host has finished its run. The default
is false.
* --help:
Print this help message
* --host:
A specific host to which to connect. This flag can be specified more
than once.
* --ignoreschedules:
Whether the client should ignore schedules when running its
configuration. This can be used to force the client to perform work it
would not normally perform so soon. The default is false.
* --parallel:
How parallel to make the connections. Parallelization is provided by
forking for each client to which to connect. The default is 1, meaning
serial execution.
* --tag:
Specify a tag for selecting the objects to apply. Does not work with
the --test option.
* --test:
Print the hosts you would connect to but do not actually connect. This
option requires LDAP support at this point.
* --ping:
Do a ICMP echo against the target host. Skip hosts that don't respond
to ping.
EXAMPLE
-------
$ sudo puppet kick -p 10 -t remotefile -t webserver host1 host2
AUTHOR
------
Luke Kanies
COPYRIGHT
---------
Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License
HELP
end
def run_command
@hosts += command_line.args
options[:test] ? test : main
end
def test
puts "Skipping execution in test mode"
exit(0)
end
def main
- require 'puppet/network/client'
-
Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap?
require 'puppet/util/ldap/connection'
todo = @hosts.dup
failures = []
# Now do the actual work
go = true
while go
# If we don't have enough children in process and we still have hosts left to
# do, then do the next host.
if @children.length < options[:parallel] and ! todo.empty?
host = todo.shift
pid = fork do
run_for_host(host)
end
@children[pid] = host
else
# Else, see if we can reap a process.
begin
pid = Process.wait
if host = @children[pid]
# Remove our host from the list of children, so the parallelization
# continues working.
@children.delete(pid)
failures << host if $CHILD_STATUS.exitstatus != 0
print "#{host} finished with exit code #{$CHILD_STATUS.exitstatus}\n"
else
$stderr.puts "Could not find host for PID #{pid} with status #{$CHILD_STATUS.exitstatus}"
end
rescue Errno::ECHILD
# There are no children left, so just exit unless there are still
# children left to do.
next unless todo.empty?
if failures.empty?
puts "Finished"
exit(0)
else
puts "Failed: #{failures.join(", ")}"
exit(3)
end
end
end
end
end
def run_for_host(host)
if options[:ping]
out = %x{ping -c 1 #{host}}
unless $CHILD_STATUS == 0
$stderr.print "Could not contact #{host}\n"
exit($CHILD_STATUS)
end
end
require 'puppet/run'
Puppet::Run.indirection.terminus_class = :rest
port = Puppet[:puppetport]
url = ["https://#{host}:#{port}", "production", "run", host].join('/')
print "Triggering #{host}\n"
begin
run_options = {
:tags => @tags,
:background => ! options[:foreground],
:ignoreschedules => options[:ignoreschedules]
}
run = Puppet::Run.indirection.save(Puppet::Run.new( run_options ), url)
puts "Getting status"
result = run.status
puts "status is #{result}"
rescue => detail
puts detail.backtrace if Puppet[:trace]
$stderr.puts "Host #{host} failed: #{detail}\n"
exit(2)
end
case result
when "success";
exit(0)
when "running"
$stderr.puts "Host #{host} is already running"
exit(3)
else
$stderr.puts "Host #{host} returned unknown answer '#{result}'"
exit(12)
end
end
def initialize(*args)
super
@hosts = []
@classes = []
@tags = []
end
def preinit
[:INT, :TERM].each do |signal|
Signal.trap(signal) do
$stderr.puts "Cancelling"
exit(1)
end
end
options[:parallel] = 1
options[:verbose] = true
options[:fqdn] = true
options[:ignoreschedules] = false
options[:foreground] = false
end
def setup
if options[:debug]
Puppet::Util::Log.level = :debug
else
Puppet::Util::Log.level = :info
end
# Now parse the config
Puppet.parse_config
if Puppet[:node_terminus] == "ldap" and (options[:all] or @classes)
if options[:all]
@hosts = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name }
puts "all: #{@hosts.join(", ")}"
else
@hosts = []
@classes.each do |klass|
list = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name }
puts "#{klass}: #{list.join(", ")}"
@hosts += list
end
end
elsif ! @classes.empty?
$stderr.puts "You must be using LDAP to specify host classes"
exit(24)
end
@children = {}
# If we get a signal, then kill all of our children and get out.
[:INT, :TERM].each do |signal|
Signal.trap(signal) do
Puppet.notice "Caught #{signal}; shutting down"
@children.each do |pid, host|
Process.kill("INT", pid)
end
waitall
exit(1)
end
end
end
end
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 6d2ac86a9..09d735672 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -1,892 +1,941 @@
# The majority of the system configuration parameters are set in this file.
module Puppet
setdefaults(:main,
:confdir => [Puppet.run_mode.conf_dir, "The main Puppet configuration directory. The default for this parameter is calculated based on the user. If the process
is running as root or the user that Puppet is supposed to run as, it defaults to a system directory, but if it's running as any other user,
it defaults to being in the user's home directory."],
:vardir => [Puppet.run_mode.var_dir, "Where Puppet stores dynamic and growing data. The default for this parameter is calculated specially, like `confdir`_."],
:name => [Puppet.application_name.to_s, "The name of the application, if we are running as one. The
default is essentially $0 without the path or `.rb`."],
:run_mode => [Puppet.run_mode.name.to_s, "The effective 'run mode' of the application: master, agent, or user."]
)
setdefaults(:main, :logdir => Puppet.run_mode.logopts)
setdefaults(:main,
:trace => [false, "Whether to print stack traces on some errors"],
:autoflush => {
:default => false,
:desc => "Whether log files should always flush to disk.",
:hook => proc { |value| Log.autoflush = value }
},
:syslogfacility => ["daemon", "What syslog facility to use when logging to
syslog. Syslog has a fixed list of valid facilities, and you must
choose one of those; you cannot just make one up."],
:statedir => { :default => "$vardir/state",
:mode => 01755,
:desc => "The directory where Puppet state is stored. Generally,
this directory can be removed without causing harm (although it
might result in spurious service restarts)."
},
:rundir => {
:default => Puppet.run_mode.run_dir,
:mode => 01777,
:desc => "Where Puppet PID files are kept."
},
:genconfig => [false,
"Whether to just print a configuration to stdout and exit. Only makes
sense when used interactively. Takes into account arguments specified
on the CLI."],
:genmanifest => [false,
"Whether to just print a manifest to stdout and exit. Only makes
sense when used interactively. Takes into account arguments specified
on the CLI."],
:configprint => ["",
"Print the value of a specific configuration parameter. If a
parameter is provided for this, then the value is printed and puppet
exits. Comma-separate multiple values. For a list of all values,
specify 'all'. This feature is only available in Puppet versions
higher than 0.18.4."],
:color => {
:default => (Puppet.features.microsoft_windows? ? "false" : "ansi"),
:type => :setting,
:desc => "Whether to use colors when logging to the console.
Valid values are `ansi` (equivalent to `true`), `html` (mostly
used during testing with TextMate), and `false`, which produces
no color.",
},
:mkusers => [false,
"Whether to create the necessary user and group that puppet agent will
run as."],
:manage_internal_file_permissions => [true,
"Whether Puppet should manage the owner, group, and mode of files
it uses internally"
],
:onetime => {:default => false,
:desc => "Run the configuration once, rather than as a long-running
daemon. This is useful for interactively running puppetd.",
:short => 'o'
},
:path => {:default => "none",
:desc => "The shell search path. Defaults to whatever is inherited
from the parent process.",
:call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
:hook => proc do |value|
ENV["PATH"] = "" if ENV["PATH"].nil?
ENV["PATH"] = value unless value == "none"
paths = ENV["PATH"].split(File::PATH_SEPARATOR)
%w{/usr/sbin /sbin}.each do |path|
ENV["PATH"] += File::PATH_SEPARATOR + path unless paths.include?(path)
end
value
end
},
:libdir => {:default => "$vardir/lib",
:desc => "An extra search path for Puppet. This is only useful
for those files that Puppet will load on demand, and is only
guaranteed to work for those cases. In fact, the autoload
mechanism is responsible for making sure this directory
is in Ruby's search path",
:call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
:hook => proc do |value|
$LOAD_PATH.delete(@oldlibdir) if defined?(@oldlibdir) and $LOAD_PATH.include?(@oldlibdir)
@oldlibdir = value
$LOAD_PATH << value
end
},
:ignoreimport => [false, "A parameter that can be used in commit
hooks, since it enables you to parse-check a single file rather
than requiring that all files exist."],
:authconfig => [ "$confdir/namespaceauth.conf",
"The configuration file that defines the rights to the different
namespaces and methods. This can be used as a coarse-grained
authorization system for both `puppet agent` and `puppet master`."
],
:environment => {:default => "production", :desc => "The environment Puppet is running in. For clients
(e.g., `puppet agent`) this determines the environment itself, which
is used to find modules and much more. For servers (i.e., `puppet master`) this provides the default environment for nodes
we know nothing about."
},
:diff_args => ["-u", "Which arguments to pass to the diff command when printing differences between files."],
:diff => ["diff", "Which diff command to use when printing differences between files."],
:show_diff => [false, "Whether to print a contextual diff when files are being replaced. The diff
is printed on stdout, so this option is meaningless unless you are running Puppet interactively.
This feature currently requires the `diff/lcs` Ruby library."],
:daemonize => {
:default => (Puppet.features.microsoft_windows? ? false : true),
:desc => "Send the process into the background. This is the default.",
:short => "D",
:hook => proc do |value|
if value and Puppet.features.microsoft_windows?
raise "Cannot daemonize on Windows"
end
end
},
:maximum_uid => [4294967290, "The maximum allowed UID. Some platforms use negative UIDs
but then ship with tools that do not know how to handle signed ints, so the UIDs show up as
huge numbers that can then not be fed back into the system. This is a hackish way to fail in a
slightly more useful way when that happens."],
:route_file => ["$confdir/routes.yaml", "The YAML file containing indirector route configuration."],
:node_terminus => ["plain", "Where to find information about nodes."],
:catalog_terminus => ["compiler", "Where to get node catalogs. This is useful to change if, for instance,
you'd like to pre-compile catalogs and store them in memcached or some other easily-accessed store."],
:facts_terminus => {
:default => Puppet.application_name.to_s == "master" ? 'yaml' : 'facter',
:desc => "The node facts terminus.",
:hook => proc do |value|
require 'puppet/node/facts'
if value.to_s == "rest"
Puppet::Node::Facts.indirection.cache_class = :yaml
end
end
},
:inventory_terminus => [ "$facts_terminus", "Should usually be the same as the facts terminus" ],
:httplog => { :default => "$logdir/http.log",
:owner => "root",
:mode => 0640,
:desc => "Where the puppet agent web server logs."
},
:http_proxy_host => ["none",
"The HTTP proxy host to use for outgoing connections. Note: You
may need to use a FQDN for the server hostname when using a proxy."],
:http_proxy_port => [3128, "The HTTP proxy port to use for outgoing connections"],
:filetimeout => [ 15,
"The minimum time to wait (in seconds) between checking for updates in
configuration files. This timeout determines how quickly Puppet checks whether
a file (such as manifests or templates) has changed on disk."
],
:queue_type => ["stomp", "Which type of queue to use for asynchronous processing."],
:queue_type => ["stomp", "Which type of queue to use for asynchronous processing."],
:queue_source => ["stomp://localhost:61613/", "Which type of queue to use for asynchronous processing. If your stomp server requires
authentication, you can include it in the URI as long as your stomp client library is at least 1.1.1"],
:async_storeconfigs => {:default => false, :desc => "Whether to use a queueing system to provide asynchronous database integration.
Requires that `puppetqd` be running and that 'PSON' support for ruby be installed.",
:hook => proc do |value|
if value
# This reconfigures the terminii for Node, Facts, and Catalog
Puppet.settings[:storeconfigs] = true
# But then we modify the configuration
Puppet::Resource::Catalog.indirection.cache_class = :queue
else
raise "Cannot disable asynchronous storeconfigs in a running process"
end
end
},
:thin_storeconfigs => {:default => false, :desc =>
"Boolean; wether storeconfigs store in the database only the facts and exported resources.
If true, then storeconfigs performance will be higher and still allow exported/collected
resources, but other usage external to Puppet might not work",
:hook => proc do |value|
Puppet.settings[:storeconfigs] = true if value
end
},
:config_version => ["", "How to determine the configuration version. By default, it will be the
time that the configuration is parsed, but you can provide a shell script to override how the
version is determined. The output of this script will be added to every log message in the
reports, allowing you to correlate changes on your hosts to the source version on the server."],
:zlib => [true,
"Boolean; whether to use the zlib library",
],
:prerun_command => ["", "A command to run before every agent run. If this command returns a non-zero
return code, the entire Puppet run will fail."],
:postrun_command => ["", "A command to run after every agent run. If this command returns a non-zero
return code, the entire Puppet run will be considered to have failed, even though it might have
performed work during the normal run."],
:freeze_main => [false, "Freezes the 'main' class, disallowing any code to be added to it. This
essentially means that you can't have any code outside of a node, class, or definition other
than in the site manifest."]
)
hostname = Facter["hostname"].value
domain = Facter["domain"].value
if domain and domain != ""
fqdn = [hostname, domain].join(".")
else
fqdn = hostname
end
Puppet.setdefaults(
:main,
# We have to downcase the fqdn, because the current ssl stuff (as oppsed to in master) doesn't have good facilities for
# manipulating naming.
:certname => {:default => fqdn.downcase, :desc => "The name to use when handling certificates. Defaults
to the fully qualified domain name.",
:call_on_define => true, # Call our hook with the default value, so we're always downcased
:hook => proc { |value| raise(ArgumentError, "Certificate names must be lower case; see #1168") unless value == value.downcase }},
- :certdnsnames => ['', "The DNS names on the Server certificate as a colon-separated list.
- If it's anything other than an empty string, it will be used as an alias in the created
- certificate. By default, only the server gets an alias set up, and only for 'puppet'."],
+ :certdnsnames => {
+ :default => '',
+ :hook => proc do |value|
+ unless value.nil? or value == '' then
+ Puppet.warning <<WARN
+The `certdnsnames` setting is no longer functional,
+after CVE-2011-3872. We ignore the value completely.
+
+For your own certificate request you can set `dns_alt_names` in the
+configuration and it will apply locally. There is no configuration option to
+set DNS alt names, or any other `subjectAltName` value, for another nodes
+certificate.
+
+Alternately you can use the `--dns_alt_names` command line option to set the
+labels added while generating your own CSR.
+WARN
+ end
+ end,
+ :desc => <<EOT
+The `certdnsnames` setting is no longer functional,
+after CVE-2011-3872. We ignore the value completely.
+
+For your own certificate request you can set `dns_alt_names` in the
+configuration and it will apply locally. There is no configuration option to
+set DNS alt names, or any other `subjectAltName` value, for another nodes
+certificate.
+
+Alternately you can use the `--dns_alt_names` command line option to set the
+labels added while generating your own CSR.
+EOT
+ },
+ :dns_alt_names => {
+ :default => '',
+ :desc => <<EOT,
+The comma-separated list of alternative DNS names to use for the local host.
+
+When the node generates a CSR for itself, these are added to the request
+as the desired `subjectAltName` in the certificate: additional DNS labels
+that the certificate is also valid answering as.
+
+This is generally required if you use a non-hostname `certname`, or if you
+want to use `puppet kick` or `puppet resource -H` and the primary certname
+does not match the DNS name you use to communicate with the host.
+
+This is unnecessary for agents, unless you intend to use them as a server for
+`puppet kick` or remote `puppet resource` management.
+
+It is rarely necessary for servers; it is usually helpful only if you need to
+have a pool of multiple load balanced masters, or for the same master to
+respond on two physically separate networks under different names.
+EOT
+ },
:certdir => {
:default => "$ssldir/certs",
:owner => "service",
:desc => "The certificate directory."
},
:ssldir => {
:default => "$confdir/ssl",
:mode => 0771,
:owner => "service",
:desc => "Where SSL certificates are kept."
},
:publickeydir => {
:default => "$ssldir/public_keys",
:owner => "service",
:desc => "The public key directory."
},
:requestdir => {
:default => "$ssldir/certificate_requests",
:owner => "service",
:desc => "Where host certificate requests are stored."
},
:privatekeydir => { :default => "$ssldir/private_keys",
:mode => 0750,
:owner => "service",
:desc => "The private key directory."
},
:privatedir => { :default => "$ssldir/private",
:mode => 0750,
:owner => "service",
:desc => "Where the client stores private certificate information."
},
:passfile => { :default => "$privatedir/password",
:mode => 0640,
:owner => "service",
:desc => "Where puppet agent stores the password for its private key.
Generally unused."
},
:hostcsr => { :default => "$ssldir/csr_$certname.pem",
:mode => 0644,
:owner => "service",
:desc => "Where individual hosts store and look for their certificate requests."
},
:hostcert => { :default => "$certdir/$certname.pem",
:mode => 0644,
:owner => "service",
:desc => "Where individual hosts store and look for their certificates."
},
:hostprivkey => { :default => "$privatekeydir/$certname.pem",
:mode => 0600,
:owner => "service",
:desc => "Where individual hosts store and look for their private key."
},
:hostpubkey => { :default => "$publickeydir/$certname.pem",
:mode => 0644,
:owner => "service",
:desc => "Where individual hosts store and look for their public key."
},
:localcacert => { :default => "$certdir/ca.pem",
:mode => 0644,
:owner => "service",
:desc => "Where each client stores the CA certificate."
},
:hostcrl => { :default => "$ssldir/crl.pem",
:mode => 0644,
:owner => "service",
:desc => "Where the host's certificate revocation list can be found.
This is distinct from the certificate authority's CRL."
},
:certificate_revocation => [true, "Whether certificate revocation should be supported by downloading a Certificate Revocation List (CRL)
to all clients. If enabled, CA chaining will almost definitely not work."]
)
setdefaults(
:ca,
:ca_name => ["Puppet CA: $certname", "The name to use the Certificate Authority certificate."],
:cadir => { :default => "$ssldir/ca",
:owner => "service",
:group => "service",
:mode => 0770,
:desc => "The root directory for the certificate authority."
},
:cacert => { :default => "$cadir/ca_crt.pem",
:owner => "service",
:group => "service",
:mode => 0660,
:desc => "The CA certificate."
},
:cakey => { :default => "$cadir/ca_key.pem",
:owner => "service",
:group => "service",
:mode => 0660,
:desc => "The CA private key."
},
:capub => { :default => "$cadir/ca_pub.pem",
:owner => "service",
:group => "service",
:desc => "The CA public key."
},
:cacrl => { :default => "$cadir/ca_crl.pem",
:owner => "service",
:group => "service",
:mode => 0664,
:desc => "The certificate revocation list (CRL) for the CA. Will be used if present but otherwise ignored.",
:hook => proc do |value|
if value == 'false'
Puppet.warning "Setting the :cacrl to 'false' is deprecated; Puppet will just ignore the crl if yours is missing"
end
end
},
:caprivatedir => { :default => "$cadir/private",
:owner => "service",
:group => "service",
:mode => 0770,
:desc => "Where the CA stores private certificate information."
},
:csrdir => { :default => "$cadir/requests",
:owner => "service",
:group => "service",
:desc => "Where the CA stores certificate requests"
},
:signeddir => { :default => "$cadir/signed",
:owner => "service",
:group => "service",
:mode => 0770,
:desc => "Where the CA stores signed certificates."
},
:capass => { :default => "$caprivatedir/ca.pass",
:owner => "service",
:group => "service",
:mode => 0660,
:desc => "Where the CA stores the password for the private key"
},
:serial => { :default => "$cadir/serial",
:owner => "service",
:group => "service",
:mode => 0644,
:desc => "Where the serial number for certificates is stored."
},
:autosign => { :default => "$confdir/autosign.conf",
:mode => 0644,
:desc => "Whether to enable autosign. Valid values are true (which
autosigns any key request, and is a very bad idea), false (which
never autosigns any key request), and the path to a file, which
uses that configuration file to determine which keys to sign."},
:allow_duplicate_certs => [false, "Whether to allow a new certificate
request to overwrite an existing certificate."],
:ca_days => ["", "How long a certificate should be valid.
This parameter is deprecated, use ca_ttl instead"],
:ca_ttl => ["5y", "The default TTL for new certificates; valid values
must be an integer, optionally followed by one of the units
'y' (years of 365 days), 'd' (days), 'h' (hours), or
's' (seconds). The unit defaults to seconds. If this parameter
is set, ca_days is ignored. Examples are '3600' (one hour)
and '1825d', which is the same as '5y' (5 years) "],
:ca_md => ["md5", "The type of hash used in certificates."],
:req_bits => [2048, "The bit length of the certificates."],
:keylength => [1024, "The bit length of keys."],
:cert_inventory => {
:default => "$cadir/inventory.txt",
:mode => 0644,
:owner => "service",
:group => "service",
:desc => "A Complete listing of all certificates"
}
)
# Define the config default.
setdefaults(
Puppet.settings[:name],
:config => ["$confdir/puppet.conf",
"The configuration file for #{Puppet[:name]}."],
:pidfile => ["$rundir/$name.pid", "The pid file"],
:bindaddress => ["", "The address a listening server should bind to. Mongrel servers
default to 127.0.0.1 and WEBrick defaults to 0.0.0.0."],
:servertype => {:default => "webrick", :desc => "The type of server to use. Currently supported
options are webrick and mongrel. If you use mongrel, you will need
a proxy in front of the process or processes, since Mongrel cannot
speak SSL.",
:call_on_define => true, # Call our hook with the default value, so we always get the correct bind address set.
:hook => proc { |value| value == "webrick" ? Puppet.settings[:bindaddress] = "0.0.0.0" : Puppet.settings[:bindaddress] = "127.0.0.1" if Puppet.settings[:bindaddress] == "" }
}
)
setdefaults(:master,
:user => ["puppet", "The user puppet master should run as."],
:group => ["puppet", "The group puppet master should run as."],
:manifestdir => ["$confdir/manifests", "Where puppet master looks for its manifests."],
:manifest => ["$manifestdir/site.pp", "The entry-point manifest for puppet master."],
:code => ["", "Code to parse directly. This is essentially only used
by `puppet`, and should only be set if you're writing your own Puppet
executable"],
:masterlog => { :default => "$logdir/puppetmaster.log",
:owner => "service",
:group => "service",
:mode => 0660,
:desc => "Where puppet master logs. This is generally not used,
since syslog is the default log destination."
},
:masterhttplog => { :default => "$logdir/masterhttp.log",
:owner => "service",
:group => "service",
:mode => 0660,
:create => true,
:desc => "Where the puppet master web server logs."
},
:masterport => [8140, "Which port puppet master listens on."],
:node_name => ["cert", "How the puppet master determines the client's identity
and sets the 'hostname', 'fqdn' and 'domain' facts for use in the manifest,
in particular for determining which 'node' statement applies to the client.
Possible values are 'cert' (use the subject's CN in the client's
certificate) and 'facter' (use the hostname that the client
reported in its facts)"],
:bucketdir => {
:default => "$vardir/bucket",
:mode => 0750,
:owner => "service",
:group => "service",
:desc => "Where FileBucket files are stored."
},
:rest_authconfig => [ "$confdir/auth.conf",
"The configuration file that defines the rights to the different
rest indirections. This can be used as a fine-grained
authorization system for `puppet master`."
],
:ca => [true, "Wether the master should function as a certificate authority."],
:modulepath => {
:default => "$confdir/modules#{File::PATH_SEPARATOR}/usr/share/puppet/modules",
:desc => "The search path for modules as a list of directories separated by the '#{File::PATH_SEPARATOR}' character.",
:type => :setting # We don't want this to be considered a file, since it's multiple files.
},
:ssl_client_header => ["HTTP_X_CLIENT_DN", "The header containing an authenticated
client's SSL DN. Only used with Mongrel. This header must be set by the proxy
to the authenticated client's SSL DN (e.g., `/CN=puppet.puppetlabs.com`).
See http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel for more information."],
:ssl_client_verify_header => ["HTTP_X_CLIENT_VERIFY", "The header containing the status
message of the client verification. Only used with Mongrel. This header must be set by the proxy
to 'SUCCESS' if the client successfully authenticated, and anything else otherwise.
See http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel for more information."],
# To make sure this directory is created before we try to use it on the server, we need
# it to be in the server section (#1138).
:yamldir => {:default => "$vardir/yaml", :owner => "service", :group => "service", :mode => "750",
:desc => "The directory in which YAML data is stored, usually in a subdirectory."},
:server_datadir => {:default => "$vardir/server_data", :owner => "service", :group => "service", :mode => "750",
:desc => "The directory in which serialized data is stored, usually in a subdirectory."},
:reports => ["store",
"The list of reports to generate. All reports are looked for
in `puppet/reports/name.rb`, and multiple report names should be
comma-separated (whitespace is okay)."
],
:reportdir => {:default => "$vardir/reports",
:mode => 0750,
:owner => "service",
:group => "service",
:desc => "The directory in which to store reports
received from the client. Each client gets a separate
subdirectory."},
:reporturl => ["http://localhost:3000/reports/upload",
"The URL used by the http reports processor to send reports"],
:fileserverconfig => ["$confdir/fileserver.conf", "Where the fileserver configuration is stored."],
:strict_hostname_checking => [false, "Whether to only search for the complete
hostname as it is in the certificate when searching for node information
in the catalogs."]
)
setdefaults(:metrics,
:rrddir => {:default => "$vardir/rrd",
:mode => 0750,
:owner => "service",
:group => "service",
:desc => "The directory where RRD database files are stored.
Directories for each reporting host will be created under
this directory."
},
:rrdinterval => ["$runinterval", "How often RRD should expect data.
This should match how often the hosts report back to the server."]
)
setdefaults(:device,
:devicedir => {:default => "$vardir/devices", :mode => "750", :desc => "The root directory of devices' $vardir"},
:deviceconfig => ["$confdir/device.conf","Path to the device config file for puppet device"]
)
setdefaults(:agent,
:node_name_value => { :default => "$certname",
:desc => "The explicit value used for the node name for all requests the agent
makes to the master. WARNING: This setting is mutually exclusive with
node_name_fact. Changing this setting also requires changes to the default
auth.conf configuration on the Puppet Master. Please see
http://links.puppetlabs.com/node_name_value for more information."
},
:node_name_fact => { :default => "",
:desc => "The fact name used to determine the node name used for all requests the agent
makes to the master. WARNING: This setting is mutually exclusive with
node_name_value. Changing this setting also requires changes to the default
auth.conf configuration on the Puppet Master. Please see
http://links.puppetlabs.com/node_name_fact for more information.",
:hook => proc do |value|
if !value.empty? and Puppet[:node_name_value] != Puppet[:certname]
raise "Cannot specify both the node_name_value and node_name_fact settings"
end
end
},
:localconfig => { :default => "$statedir/localconfig",
:owner => "root",
:mode => 0660,
:desc => "Where puppet agent caches the local configuration. An
extension indicating the cache format is added automatically."},
:statefile => { :default => "$statedir/state.yaml",
:mode => 0660,
:desc => "Where puppet agent and puppet master store state associated
with the running configuration. In the case of puppet master,
this file reflects the state discovered through interacting
with clients."
},
:clientyamldir => {:default => "$vardir/client_yaml", :mode => "750", :desc => "The directory in which client-side YAML data is stored."},
:client_datadir => {:default => "$vardir/client_data", :mode => "750", :desc => "The directory in which serialized data is stored on the client."},
:classfile => { :default => "$statedir/classes.txt",
:owner => "root",
:mode => 0644,
:desc => "The file in which puppet agent stores a list of the classes
associated with the retrieved configuration. Can be loaded in
the separate `puppet` executable using the `--loadclasses`
option."},
:resourcefile => { :default => "$statedir/resources.txt",
:owner => "root",
:mode => 0644,
:desc => "The file in which puppet agent stores a list of the resources
associated with the retrieved configuration." },
:puppetdlog => { :default => "$logdir/puppetd.log",
:owner => "root",
: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"],
:ignoreschedules => [false,
"Boolean; whether puppet agent should ignore schedules. This is useful
for initial puppet agent runs."],
:puppetport => [8139, "Which port puppet agent listens on."],
:noop => [false, "Whether puppet agent should be run in noop mode."],
:runinterval => [1800, # 30 minutes
"How often puppet agent applies the client configuration; in seconds.
Note that a runinterval of 0 means \"run continuously\" rather than
\"never run.\" If you want puppet agent to never run, you should start
it with the `--no-client` option."],
:listen => [false, "Whether puppet agent should listen for
connections. If this is true, then puppet agent will accept incoming
REST API requests, subject to the default ACLs and the ACLs set in
the `rest_authconfig` file. Puppet agent can respond usefully to
requests on the `run`, `facts`, `certificate`, and `resource` endpoints."],
:ca_server => ["$server", "The server to use for certificate
authority requests. It's a separate server because it cannot
and does not need to horizontally scale."],
:ca_port => ["$masterport", "The port to use for the certificate authority."],
:catalog_format => {
:default => "",
:desc => "(Deprecated for 'preferred_serialization_format') What format to
use to dump the catalog. Only supports 'marshal' and 'yaml'. Only
matters on the client, since it asks the server for a specific format.",
:hook => proc { |value|
if value
Puppet.warning "Setting 'catalog_format' is deprecated; use 'preferred_serialization_format' instead."
Puppet.settings[:preferred_serialization_format] = value
end
}
},
:preferred_serialization_format => ["pson", "The preferred means of serializing
ruby instances for passing over the wire. This won't guarantee that all
instances will be serialized using this method, since not all classes
can be guaranteed to support this format, but it will be used for all
classes that support it."],
:puppetdlockfile => [ "$statedir/puppetdlock", "A lock file to temporarily stop puppet agent from doing anything."],
:usecacheonfailure => [true,
"Whether to use the cached configuration when the remote
configuration will not compile. This option is useful for testing
new configurations, where you want to fix the broken configuration
rather than reverting to a known-good one."
],
:use_cached_catalog => [false,
"Whether to only use the cached catalog rather than compiling a new catalog
on every run. Puppet can be run with this enabled by default and then selectively
disabled when a recompile is desired."],
:ignorecache => [false,
"Ignore cache and always recompile the configuration. This is
useful for testing new configurations, where the local cache may in
fact be stale even if the timestamps are up to date - if the facts
change or if the server changes."
],
:downcasefacts => [false, "Whether facts should be made all lowercase when sent to the server."],
:dynamicfacts => ["memorysize,memoryfree,swapsize,swapfree",
"Facts that are dynamic; these facts will be ignored when deciding whether
changed facts should result in a recompile. Multiple facts should be
comma-separated."],
:splaylimit => ["$runinterval",
"The maximum time to delay before runs. Defaults to being the same as the
run interval."],
:splay => [false,
"Whether to sleep for a pseudo-random (but consistent) amount of time before
a run."],
:clientbucketdir => {
:default => "$vardir/clientbucket",
:mode => 0750,
:desc => "Where FileBucket files are stored locally."
},
:configtimeout => [120,
"How long the client should wait for the configuration to be retrieved
before considering it a failure. This can help reduce flapping if too
many clients contact the server at one time."
],
:reportserver => {
:default => "$server",
:call_on_define => false,
:desc => "(Deprecated for 'report_server') The server to which to send transaction reports.",
:hook => proc do |value|
Puppet.settings[:report_server] = value if value
end
},
:report_server => ["$server",
"The server to send transaction reports to."
],
:report_port => ["$masterport",
"The port to communicate with the report_server."
],
:inventory_server => ["$server",
"The server to send facts to."
],
:inventory_port => ["$masterport",
"The port to communicate with the inventory_server."
],
:report => [true,
"Whether to send reports after every transaction."
],
:lastrunfile => { :default => "$statedir/last_run_summary.yaml",
:mode => 0660,
:desc => "Where puppet agent stores the last run report summary in yaml format."
},
:lastrunreport => { :default => "$statedir/last_run_report.yaml",
:mode => 0660,
:desc => "Where puppet agent stores the last run report in yaml format."
},
:graph => [false, "Whether to create dot graph files for the different
configuration graphs. These dot files can be interpreted by tools
like OmniGraffle or dot (which is part of ImageMagick)."],
:graphdir => ["$statedir/graphs", "Where to store dot-outputted graphs."],
:http_compression => [false, "Allow http compression in REST communication with the master.
This setting might improve performance for agent -> master communications over slow WANs.
Your puppet master needs to support compression (usually by activating some settings in a reverse-proxy
in front of the puppet master, which rules out webrick).
It is harmless to activate this settings if your master doesn't support
compression, but if it supports it, this setting might reduce performance on high-speed LANs."]
)
setdefaults(:inspect,
:archive_files => [false, "During an inspect run, whether to archive files whose contents are audited to a file bucket."],
:archive_file_server => ["$server", "During an inspect run, the file bucket server to archive files to if archive_files is set."]
)
# Plugin information.
setdefaults(
:main,
:plugindest => ["$libdir",
"Where Puppet should store plugins that it pulls down from the central
server."],
:pluginsource => ["puppet://$server/plugins",
"From where to retrieve plugins. The standard Puppet `file` type
is used for retrieval, so anything that is a valid file source can
be used here."],
:pluginsync => [false, "Whether plugins should be synced with the central server."],
:pluginsignore => [".svn CVS .git", "What files to ignore when pulling down plugins."]
)
# Central fact information.
setdefaults(
:main,
:factpath => {:default => "$vardir/lib/facter#{File::PATH_SEPARATOR}$vardir/facts",
:desc => "Where Puppet should look for facts. Multiple directories should
be colon-separated, like normal PATH variables.",
:call_on_define => true, # Call our hook with the default value, so we always get the value added to facter.
:type => :setting, # Don't consider it a file, because it could be multiple colon-separated files
:hook => proc { |value| Facter.search(value) if Facter.respond_to?(:search) }},
:factdest => ["$vardir/facts/",
"Where Puppet should store facts that it pulls down from the central
server."],
:factsource => ["puppet://$server/facts/",
"From where to retrieve facts. The standard Puppet `file` type
is used for retrieval, so anything that is a valid file source can
be used here."],
:factsync => [false, "Whether facts should be synced with the central server."],
:factsignore => [".svn CVS", "What files to ignore when pulling down facts."]
)
setdefaults(
:tagmail,
:tagmap => ["$confdir/tagmail.conf", "The mapping between reporting tags and email addresses."],
:sendmail => [which('sendmail') || '', "Where to find the sendmail binary with which to send email."],
:reportfrom => ["report@" + [Facter["hostname"].value, Facter["domain"].value].join("."), "The 'from' email address for the reports."],
:smtpserver => ["none", "The server through which to send email reports."]
)
setdefaults(
:rails,
:dblocation => { :default => "$statedir/clientconfigs.sqlite3",
:mode => 0660,
:owner => "service",
:group => "service",
:desc => "The database cache for client configurations. Used for
querying within the language."
},
:dbadapter => [ "sqlite3", "The type of database to use." ],
:dbmigrate => [ false, "Whether to automatically migrate the database." ],
:dbname => [ "puppet", "The name of the database to use." ],
:dbserver => [ "localhost", "The database server for caching. Only
used when networked databases are used."],
:dbport => [ "", "The database password for caching. Only
used when networked databases are used."],
:dbuser => [ "puppet", "The database user for caching. Only
used when networked databases are used."],
:dbpassword => [ "puppet", "The database password for caching. Only
used when networked databases are used."],
:dbconnections => [ '', "The number of database connections for networked
databases. Will be ignored unless the value is a positive integer."],
:dbsocket => [ "", "The database socket location. Only used when networked
databases are used. Will be ignored if the value is an empty string."],
:railslog => {:default => "$logdir/rails.log",
:mode => 0600,
:owner => "service",
:group => "service",
:desc => "Where Rails-specific logs are sent"
},
:rails_loglevel => ["info", "The log level for Rails connections. The value must be
a valid log level within Rails. Production environments normally use `info`
and other environments normally use `debug`."]
)
setdefaults(
:couchdb,
:couchdb_url => ["http://127.0.0.1:5984/puppet", "The url where the puppet couchdb database will be created"]
)
setdefaults(
:transaction,
:tags => ["", "Tags to use to find resources. If this is set, then
only resources tagged with the specified tags will be applied.
Values must be comma-separated."],
:evaltrace => [false, "Whether each resource should log when it is
being evaluated. This allows you to interactively see exactly
what is being done."],
:summarize => [false,
"Whether to print a transaction summary."
]
)
setdefaults(
:main,
:external_nodes => ["none",
"An external command that can produce node information. The output
must be a YAML dump of a hash, and that hash must have one or both of
`classes` and `parameters`, where `classes` is an array and
`parameters` is a hash. For unknown nodes, the commands should
exit with a non-zero exit code.
This command makes it straightforward to store your node mapping
information in other data sources like databases."])
setdefaults(
:ldap,
:ldapnodes => [false,
"Whether to search for node configurations in LDAP. See
http://projects.puppetlabs.com/projects/puppet/wiki/LDAP_Nodes for more information."],
:ldapssl => [false,
"Whether SSL should be used when searching for nodes.
Defaults to false because SSL usually requires certificates
to be set up on the client side."],
:ldaptls => [false,
"Whether TLS should be used when searching for nodes.
Defaults to false because TLS usually requires certificates
to be set up on the client side."],
:ldapserver => ["ldap",
"The LDAP server. Only used if `ldapnodes` is enabled."],
:ldapport => [389,
"The LDAP port. Only used if `ldapnodes` is enabled."],
:ldapstring => ["(&(objectclass=puppetClient)(cn=%s))",
"The search string used to find an LDAP node."],
:ldapclassattrs => ["puppetclass",
"The LDAP attributes to use to define Puppet classes. Values
should be comma-separated."],
:ldapstackedattrs => ["puppetvar",
"The LDAP attributes that should be stacked to arrays by adding
the values in all hierarchy elements of the tree. Values
should be comma-separated."],
:ldapattrs => ["all",
"The LDAP attributes to include when querying LDAP for nodes. All
returned attributes are set as variables in the top-level scope.
Multiple values should be comma-separated. The value 'all' returns
all attributes."],
:ldapparentattr => ["parentnode",
"The attribute to use to define the parent node."],
:ldapuser => ["",
"The user to use to connect to LDAP. Must be specified as a
full DN."],
:ldappassword => ["", "The password to use to connect to LDAP."],
:ldapbase => ["",
"The search base for LDAP searches. It's impossible to provide
a meaningful default here, although the LDAP libraries might
have one already set. Generally, it should be the 'ou=Hosts'
branch under your main directory."]
)
setdefaults(:master,
:storeconfigs => {
:default => false,
:desc => "Whether to store each client's configuration, including catalogs, facts,
and related data. This also enables the import and export of resources in
the Puppet language - a mechanism for exchange resources between nodes.
By default this uses ActiveRecord and an SQL database to store and query
the data; this, in turn, will depend on Rails being available.
You can adjust the backend using the storeconfigs_backend setting.",
# Call our hook with the default value, so we always get the libdir set.
:call_on_define => true,
:hook => proc do |value|
require 'puppet/node'
require 'puppet/node/facts'
if value
Puppet.settings[:async_storeconfigs] or
Puppet::Resource::Catalog.indirection.cache_class = :store_configs
Puppet::Node::Facts.indirection.cache_class = :store_configs
Puppet::Node.indirection.cache_class = :store_configs
Puppet::Resource.indirection.terminus_class = :store_configs
end
end
},
:storeconfigs_backend => {
:default => "active_record",
:desc => "Configure the backend terminus used for StoreConfigs.
By default, this uses the ActiveRecord store, which directly talks to the
database from within the Puppet Master process."
}
)
# This doesn't actually work right now.
setdefaults(
:parser,
:lexical => [false, "Whether to use lexical scoping (vs. dynamic)."],
:templatedir => ["$vardir/templates",
"Where Puppet looks for template files. Can be a list of colon-seperated
directories."
]
)
setdefaults(
:puppetdoc,
:document_all => [false, "Document all resources"]
)
end
diff --git a/lib/puppet/face/ca.rb b/lib/puppet/face/ca.rb
index 00591d637..6688886ab 100644
--- a/lib/puppet/face/ca.rb
+++ b/lib/puppet/face/ca.rb
@@ -1,233 +1,242 @@
require 'puppet/face'
Puppet::Face.define(:ca, '0.1.0') do
copyright "Puppet Labs", 2011
license "Apache 2 license; see COPYING"
summary "Local Puppet Certificate Authority management."
description <<-TEXT
This provides local management of the Puppet Certificate Authority.
You can use this subcommand to sign outstanding certificate requests, list
and manage local certificates, and inspect the state of the CA.
TEXT
action :list do
summary "List certificates and/or certificate requests."
description <<-TEXT
This will list the current certificates and certificate signing requests
in the Puppet CA. You will also get the fingerprint, and any certificate
verification failure reported.
TEXT
option "--[no-]all" do
summary "Include all certificates and requests."
end
option "--[no-]pending" do
summary "Include pending certificate signing requests."
end
option "--[no-]signed" do
summary "Include signed certificates."
end
option "--subject PATTERN" do
summary "Only list if the subject matches PATTERN."
description <<-TEXT
Only include certificates or requests where subject matches PATTERN.
PATTERN is interpreted as a regular expression, allowing complex
filtering of the content.
TEXT
end
when_invoked do |options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
pattern = options[:subject].nil? ? nil :
Regexp.new(options[:subject], Regexp::IGNORECASE)
pending = options[:pending].nil? ? options[:all] : options[:pending]
signed = options[:signed].nil? ? options[:all] : options[:signed]
# By default we list pending, so if nothing at all was requested...
unless pending or signed then pending = true end
hosts = []
pending and hosts += ca.waiting?
signed and hosts += ca.list
pattern and hosts = hosts.select {|hostname| pattern.match hostname }
hosts.sort.map {|host| Puppet::SSL::Host.new(host) }
end
when_rendering :console do |hosts|
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
length = hosts.map{|x| x.name.length }.max + 1
hosts.map do |host|
name = host.name.ljust(length)
if host.certificate_request then
" #{name} (#{host.certificate_request.fingerprint})"
else
begin
ca.verify(host.certificate)
"+ #{name} (#{host.certificate.fingerprint})"
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
"- #{name} (#{host.certificate.fingerprint}) (#{e.to_s})"
end
end
end.join("\n")
end
end
action :destroy do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
ca.destroy host
end
end
action :revoke do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
ca.revoke host
rescue ArgumentError => e
# This is a bit naff, but it makes the behaviour consistent with the
# destroy action. The underlying tools could be nicer for that sort
# of thing; they have fairly inconsistent reporting of failures.
raise unless e.to_s =~ /Could not find a serial number for /
"Nothing was revoked"
end
end
end
action :generate do
+ option "--dns-alt-names NAMES" do
+ summary "Additional DNS names to add to the certificate request"
+ description Puppet.settings.setting(:dns_alt_names).desc
+ end
+
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
- ca.generate host
+ ca.generate(host, :dns_alt_names => options[:dns_alt_names])
rescue RuntimeError => e
if e.to_s =~ /already has a requested certificate/
"#{host} already has a certificate request; use sign instead"
else
raise
end
rescue ArgumentError => e
if e.to_s =~ /A Certificate already exists for /
"#{host} already has a certificate"
else
raise
end
end
end
end
action :sign do
+ option("--[no-]allow-dns-alt-names") do
+ summary "Whether or not to accept DNS alt names in the certificate request"
+ end
+
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
- ca.sign host
+ ca.sign(host, options[:allow_dns_alt_names])
rescue ArgumentError => e
if e.to_s =~ /Could not find certificate request/
e.to_s
else
raise
end
end
end
end
action :print do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
ca.print host
end
end
action :fingerprint do
option "--digest ALGORITHM" do
summary "The hash algorithm to use when displaying the fingerprint"
end
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
# I want the default from the CA, not to duplicate it, but passing
# 'nil' explicitly means that we don't get that. This works...
if options.has_key? :digest
ca.fingerprint host, options[:digest]
else
ca.fingerprint host
end
rescue ArgumentError => e
raise unless e.to_s =~ /Could not find a certificate or csr for/
nil
end
end
end
action :verify do
when_invoked do |host, options|
raise "Not a CA" unless Puppet::SSL::CertificateAuthority.ca?
unless ca = Puppet::SSL::CertificateAuthority.instance
raise "Unable to fetch the CA"
end
begin
ca.verify host
{ :host => host, :valid => true }
rescue ArgumentError => e
raise unless e.to_s =~ /Could not find a certificate for/
{ :host => host, :valid => false, :error => e.to_s }
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => e
{ :host => host, :valid => false, :error => e.to_s }
end
end
when_rendering :console do |value|
if value[:valid]
nil
else
"Could not verify #{value[:host]}: #{value[:error]}"
end
end
end
end
diff --git a/lib/puppet/face/certificate.rb b/lib/puppet/face/certificate.rb
index 8019b6bea..d116796ac 100644
--- a/lib/puppet/face/certificate.rb
+++ b/lib/puppet/face/certificate.rb
@@ -1,119 +1,148 @@
require 'puppet/indirector/face'
require 'puppet/ssl/host'
Puppet::Indirector::Face.define(:certificate, '0.0.1') do
copyright "Puppet Labs", 2011
license "Apache 2 license; see COPYING"
summary "Provide access to the CA for certificate management."
description <<-EOT
This subcommand interacts with a local or remote Puppet certificate
authority. Currently, its behavior is not a full superset of `puppet
cert`; specifically, it is unable to mimic puppet cert's "clean" option,
and its "generate" action submits a CSR rather than creating a
signed certificate.
EOT
option "--ca-location LOCATION" do
required
summary "Which certificate authority to use (local or remote)."
description <<-EOT
Whether to act on the local certificate authority or one provided by a
remote puppet master. Allowed values are 'local' and 'remote.'
This option is required.
EOT
before_action do |action, args, options|
unless [:remote, :local, :only].include? options[:ca_location].to_sym
raise ArgumentError, "Valid values for ca-location are 'remote', 'local', 'only'."
end
Puppet::SSL::Host.ca_location = options[:ca_location].to_sym
end
end
action :generate do
summary "Generate a new certificate signing request."
arguments "<host>"
returns "Nothing."
description <<-EOT
Generates and submits a certificate signing request (CSR) for the
specified host. This CSR will then have to be signed by a user
with the proper authorization on the certificate authority.
Puppet agent usually handles CSR submission automatically. This action is
primarily useful for requesting certificates for individual users and
external applications.
EOT
examples <<-EOT
Request a certificate for "somenode" from the site's CA:
$ puppet certificate generate somenode.puppetlabs.lan --ca-location remote
EOT
+ # Duplicate the option here explicitly to distinguish if it was passed arg
+ # us vs. set in the config file.
+ option "--dns-alt-names NAMES" do
+ summary "Additional DNS names to add to the certificate request"
+ description Puppet.settings.setting(:dns_alt_names).desc
+ end
+
when_invoked do |name, options|
host = Puppet::SSL::Host.new(name)
- host.generate_certificate_request
- host.certificate_request.class.indirection.save(host.certificate_request)
+
+ # If dns_alt_names are specified via the command line, we will always add
+ # them. Otherwise, they will default to the config file setting iff this
+ # cert is for the host we're running on.
+
+ host.generate_certificate_request(:dns_alt_names => options[:dns_alt_names])
end
end
action :list do
summary "List all certificate signing requests."
returns <<-EOT
An array of #inspect output from CSR objects. This output is
currently messy, but does contain the names of nodes requesting
certificates. This action returns #inspect strings even when used
from the Ruby API.
EOT
when_invoked do |options|
Puppet::SSL::Host.indirection.search("*", {
:for => :certificate_request,
}).map { |h| h.inspect }
end
end
action :sign do
summary "Sign a certificate signing request for HOST."
arguments "<host>"
returns <<-EOT
A string that appears to be (but isn't) an x509 certificate.
EOT
examples <<-EOT
Sign somenode.puppetlabs.lan's certificate:
$ puppet certificate sign somenode.puppetlabs.lan --ca-location remote
EOT
+ option("--[no-]allow-dns-alt-names") do
+ summary "Whether or not to accept DNS alt names in the certificate request"
+ end
+
when_invoked do |name, options|
host = Puppet::SSL::Host.new(name)
- host.desired_state = 'signed'
- Puppet::SSL::Host.indirection.save(host)
+ if options[:ca_location] == :remote
+ if options[:allow_dns_alt_names]
+ raise ArgumentError, "--allow-dns-alt-names may not be specified with a remote CA"
+ end
+
+ host.desired_state = 'signed'
+ Puppet::SSL::Host.indirection.save(host)
+ else
+ # We have to do this case manually because we need to specify
+ # allow_dns_alt_names.
+ unless ca = Puppet::SSL::CertificateAuthority.instance
+ raise ArgumentError, "This process is not configured as a certificate authority"
+ end
+
+ ca.sign(name, options[:allow_dns_alt_names])
+ end
end
end
# Indirector action doc overrides
find = get_action(:find)
find.summary "Retrieve a certificate."
find.arguments "<host>"
find.render_as = :s
find.returns <<-EOT
An x509 SSL certificate.
Note that this action has a side effect of caching a copy of the
certificate in Puppet's `ssldir`.
EOT
destroy = get_action(:destroy)
destroy.summary "Delete a certificate."
destroy.arguments "<host>"
destroy.returns "Nothing."
destroy.description <<-EOT
Deletes a certificate. This action currently only works on the local CA.
EOT
get_action(:search).summary "Invalid for this subcommand."
get_action(:save).summary "Invalid for this subcommand."
get_action(:save).description "Invalid for this subcommand."
end
diff --git a/lib/puppet/indirector/report/processor.rb b/lib/puppet/indirector/report/processor.rb
index 7bdadcb36..dfda0f6ce 100644
--- a/lib/puppet/indirector/report/processor.rb
+++ b/lib/puppet/indirector/report/processor.rb
@@ -1,61 +1,61 @@
require 'puppet/transaction/report'
require 'puppet/indirector/code'
require 'puppet/reports'
class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
desc "Puppet's report processor. Processes the report with each of
the report types listed in the 'reports' setting."
def initialize
Puppet.settings.use(:main, :reporting, :metrics)
end
def save(request)
process(request.instance)
end
def destroy(request)
processors do |mod|
mod.destroy(request.key) if mod.respond_to?(:destroy)
end
end
private
# Process the report with each of the configured report types.
# LAK:NOTE This isn't necessarily the best design, but it's backward
# compatible and that's good enough for now.
def process(report)
- Puppet.debug "Recieved report to process from #{report.host}"
+ Puppet.debug "Received report to process from #{report.host}"
processors do |mod|
Puppet.debug "Processing report from #{report.host} with processor #{mod}"
# 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
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
def processors(&blk)
return if Puppet[:reports] == "none"
reports.each do |name|
if mod = Puppet::Reports.report(name)
yield(mod)
else
Puppet.warning "No report named '#{name}'"
end
end
end
end
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index 19daff51d..c8a45d76d 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -1,160 +1,160 @@
require 'net/http'
require 'uri'
require 'puppet/network/http_pool'
require 'puppet/network/http/api/v1'
require 'puppet/network/http/compression'
# Access objects via REST
class Puppet::Indirector::REST < Puppet::Indirector::Terminus
include Puppet::Network::HTTP::API::V1
include Puppet::Network::HTTP::Compression.module
class << self
attr_reader :server_setting, :port_setting
end
# Specify the setting that we should use to get the server name.
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
def self.port
Puppet.settings[port_setting || :masterport].to_i
end
# Figure out the content type, turn that into a format, and use the format
# to extract the body of the response.
def deserialize(response, multiple = false)
case response.code
when "404"
return nil
when /^2/
raise "No content type in http response; cannot parse" unless response['content-type']
content_type = response['content-type'].gsub(/\s*;.*$/,'') # strip any appended charset
body = uncompress_body(response)
# Convert the response to a deserialized object.
if multiple
model.convert_from_multiple(content_type, body)
else
model.convert_from(content_type, body)
end
else
# Raise the http error if we didn't get a 'success' of some kind.
raise convert_to_http_error(response)
end
end
def convert_to_http_error(response)
message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
Net::HTTPError.new(message, response)
end
# Provide appropriate headers.
def headers
add_accept_encoding({"Accept" => model.supported_formats.join(", ")})
end
def network(request)
Puppet::Network::HttpPool.http_instance(request.server || self.class.server, request.port || self.class.port)
end
[:get, :post, :head, :delete, :put].each do |method|
define_method "http_#{method}" do |request, *args|
http_request(method, request, *args)
end
end
def http_request(method, request, *args)
http_connection = network(request)
peer_certs = []
# We add the callback to collect the certificates for use in constructing
# the error message if the verification failed. This is necessary since we
# don't have direct access to the cert that we expected the connection to
# use otherwise.
#
http_connection.verify_callback = proc do |preverify_ok, ssl_context|
peer_certs << Puppet::SSL::Certificate.from_s(ssl_context.current_cert.to_pem)
preverify_ok
end
http_connection.send(method, *args)
rescue OpenSSL::SSL::SSLError => error
if error.message.include? "certificate verify failed"
raise Puppet::Error, "#{error.message}. This is often because the time is out of sync on the server or client"
elsif error.message.include? "hostname was not match"
raise unless cert = peer_certs.find { |c| c.name !~ /^puppet ca/i }
- valid_certnames = [cert.name, *cert.alternate_names].uniq
+ valid_certnames = [cert.name, *cert.subject_alt_names].uniq
msg = valid_certnames.length > 1 ? "one of #{valid_certnames.join(', ')}" : valid_certnames.first
raise Puppet::Error, "Server hostname '#{http_connection.address}' did not match server certificate; expected #{msg}"
else
raise
end
end
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)
end
result = deserialize response
result.name = request.key if result.respond_to?(:name=)
result
end
def head(request)
response = http_head(request, indirection2uri(request), headers)
case response.code
when "404"
return false
when /^2/
return true
else
# Raise the http error if we didn't get a 'success' of some kind.
raise convert_to_http_error(response)
end
end
def search(request)
unless result = deserialize(http_get(request, indirection2uri(request), headers), true)
return []
end
result
end
def destroy(request)
raise ArgumentError, "DELETE does not accept options" unless request.options.empty?
deserialize http_delete(request, indirection2uri(request), headers)
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 }))
end
private
def environment
Puppet::Node::Environment.new
end
end
diff --git a/lib/puppet/network/client.rb b/lib/puppet/network/client.rb
deleted file mode 100644
index f9c4c5fea..000000000
--- a/lib/puppet/network/client.rb
+++ /dev/null
@@ -1,174 +0,0 @@
-# the available clients
-
-require 'puppet'
-require 'puppet/network/xmlrpc/client'
-require 'puppet/util/subclass_loader'
-require 'puppet/util/methodhelper'
-require 'puppet/sslcertificates/support'
-
-require 'puppet/network/handler'
-
-require 'net/http'
-
-# Some versions of ruby don't have this method defined, which basically causes
-# us to never use ssl. Yay.
-class Net::HTTP
- def use_ssl?
- if defined?(@use_ssl)
- @use_ssl
- else
- false
- end
- end
-
- # JJM: This is a "backport" of sorts to older ruby versions which
- # do not have this accessor. See #896 for more information.
- attr_accessor :enable_post_connection_check unless Net::HTTP.method_defined? "enable_post_connection_check"
-end
-
-# The base class for all of the clients. Many clients just directly
-# call methods, but some of them need to do some extra work or
-# provide a different interface.
-class Puppet::Network::Client
- Client = self
- include Puppet::Util
- extend Puppet::Util::SubclassLoader
- include Puppet::Util::MethodHelper
-
- # This handles reading in the key and such-like.
- include Puppet::SSLCertificates::Support
-
- attr_accessor :schedule, :lastrun, :local, :stopping
-
- attr_reader :driver
-
- # Set up subclass loading
- handle_subclasses :client, "puppet/network/client"
-
- # Determine what clients look for when being passed an object for local
- # client/server stuff. E.g., you could call Client::CA.new(:CA => ca).
- def self.drivername
- @drivername ||= self.name
- end
-
- # Figure out the handler for our client.
- def self.handler
- @handler ||= Puppet::Network::Handler.handler(self.name)
- end
-
- # The class that handles xmlrpc interaction for us.
- def self.xmlrpc_client
- @xmlrpc_client ||= Puppet::Network::XMLRPCClient.handler_class(self.handler)
- end
-
- # Create our client.
- def initialize(hash)
- # to whom do we connect?
- @server = nil
-
- if hash.include?(:Cache)
- @cache = hash[:Cache]
- else
- @cache = true
- end
-
- driverparam = self.class.drivername
- if hash.include?(:Server)
- args = {:Server => hash[:Server]}
- @server = hash[:Server]
- args[:Port] = hash[:Port] || Puppet[:masterport]
-
- @driver = self.class.xmlrpc_client.new(args)
-
- self.read_cert
-
- @local = false
- elsif hash.include?(driverparam)
- @driver = hash[driverparam]
- if @driver == true
- @driver = self.class.handler.new
- end
- @local = true
- else
- raise Puppet::Network::ClientError, "#{self.class} must be passed a Server or #{driverparam}"
- end
- end
-
- # Are we a local client?
- def local?
- if @local
- true
- else
- false
- end
- end
-
- # Make sure we set the driver up when we read the cert in.
- def recycle_connection
- @driver.recycle_connection if @driver.respond_to?(:recycle_connection)
- end
-
- # A wrapper method to run and then store the last run time
- def runnow
- if self.stopping
- Puppet.notice "In shutdown progress; skipping run"
- return
- end
- begin
- self.run
- self.lastrun = Time.now.to_i
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not run #{self.class}: #{detail}"
- end
- end
-
- def run
- raise Puppet::DevError, "Client type #{self.class} did not override run"
- end
-
- def scheduled?
- if sched = self.schedule
- return sched.match?(self.lastrun)
- else
- return true
- end
- end
-
- def shutdown
- if self.stopping
- Puppet.notice "Already in shutdown"
- else
- self.stopping = true
- Puppet::Util::Storage.store if self.respond_to? :running? and self.running?
- rmpidfile
- end
- end
-
- # Start listening for events. We're pretty much just listening for
- # timer events here.
- def start
- # Create our timer. Puppet will handle observing it and such.
-
- timer = Puppet.newtimer(
-
- :interval => Puppet[:runinterval],
- :tolerance => 1,
-
- :start? => true
- ) do
- begin
- self.runnow if self.scheduled?
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not run client; got otherwise uncaught exception: #{detail}"
- end
- end
-
- # Run once before we start following the timer
- self.runnow
- end
-
- require 'puppet/network/client/proxy'
-end
-
diff --git a/lib/puppet/network/client/ca.rb b/lib/puppet/network/client/ca.rb
deleted file mode 100644
index 4c0177dfe..000000000
--- a/lib/puppet/network/client/ca.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'puppet/network/client'
-
-# Request a certificate from the remote system.
-class Puppet::Network::Client::CA < Puppet::Network::Client
- class InvalidCertificate < Puppet::Error; end
-
- def initialize(options = {})
- options = symbolize_options(options)
- unless options.include?(:Server) or options.include?(:CA)
- options[:Server] = Puppet[:ca_server]
- options[:Port] = Puppet[:ca_port]
- end
- super(options)
- end
-
- # This client is really only able to request certificates for the
- # current host. It uses the Puppet.settings settings to figure everything out.
- def request_cert
- Puppet.settings.use(:main, :ssl)
-
- if cert = read_cert
- return cert
- end
-
- begin
- cert, cacert = @driver.getcert(csr.to_pem)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error.new("Certificate retrieval failed: #{detail}")
- end
-
- if cert.nil? or cert == ""
- return nil
- end
-
- begin
- @cert = OpenSSL::X509::Certificate.new(cert)
- @cacert = OpenSSL::X509::Certificate.new(cacert)
- rescue => detail
- raise InvalidCertificate.new(
- "Invalid certificate: #{detail}"
- )
- end
-
- unless @cert.check_private_key(key)
- raise InvalidCertificate, "Certificate does not match private key. Try 'puppetca --clean #{Puppet[:certname]}' on the server."
- end
-
- # Only write the cert out if it passes validating.
- Puppet.settings.write(:hostcert) do |f| f.print cert end
- Puppet.settings.write(:localcacert) do |f| f.print cacert end
-
- @cert
- end
-end
-
diff --git a/lib/puppet/network/client/file.rb b/lib/puppet/network/client/file.rb
deleted file mode 100644
index caafb750c..000000000
--- a/lib/puppet/network/client/file.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class Puppet::Network::Client::File < Puppet::Network::Client::ProxyClient
- @handler = Puppet::Network::Handler.handler(:fileserver)
- @drivername = :FileServer
- self.mkmethods
-end
-
diff --git a/lib/puppet/network/client/proxy.rb b/lib/puppet/network/client/proxy.rb
deleted file mode 100644
index 1d565a83a..000000000
--- a/lib/puppet/network/client/proxy.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# unlike the other client classes (again, this design sucks) this class
-# is basically just a proxy class -- it calls its methods on the driver
-# and that's about it
-class Puppet::Network::Client::ProxyClient < Puppet::Network::Client
- def self.mkmethods
- interface = self.handler.interface
- namespace = interface.prefix
-
-
- interface.methods.each { |ary|
- method = ary[0]
- Puppet.debug "#{self}: defining #{namespace}.#{method}"
- define_method(method) { |*args|
- begin
- @driver.send(method, *args)
- rescue XMLRPC::FaultException => detail
- #Puppet.err "Could not call %s.%s: %s" %
- # [namespace, method, detail.faultString]
- #raise NetworkClientError,
- # "XMLRPC Error: #{detail.faultString}"
- raise NetworkClientError, detail.faultString
- end
- }
- }
- end
-end
-
diff --git a/lib/puppet/network/client/report.rb b/lib/puppet/network/client/report.rb
deleted file mode 100644
index c9afaf969..000000000
--- a/lib/puppet/network/client/report.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-class Puppet::Network::Client::Report < Puppet::Network::Client
- @handler = Puppet::Network::Handler.handler(:report)
-
- def initialize(hash = {})
- hash[:Report] = self.class.handler.new if hash.include?(:Report)
-
- super(hash)
- end
-
- # Send our report. We get the transaction report and convert it to YAML
- # as appropriate.
- def report(transreport)
- report = YAML.dump(transreport)
-
- report = CGI.escape(report) unless self.local
-
- # Now send the report
- file = nil
- benchmark(:info, "Sent transaction report") do
- file = @driver.report(report)
- end
-
- file
- end
-end
-
diff --git a/lib/puppet/network/client/runner.rb b/lib/puppet/network/client/runner.rb
deleted file mode 100644
index a4596a753..000000000
--- a/lib/puppet/network/client/runner.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class Puppet::Network::Client::Runner < Puppet::Network::Client::ProxyClient
- self.mkmethods
-
- def initialize(hash = {})
- hash[:Runner] = self.class.handler.new if hash.include?(:Runner)
-
- super(hash)
- end
-end
-
diff --git a/lib/puppet/network/client/status.rb b/lib/puppet/network/client/status.rb
deleted file mode 100644
index c24c7e3d0..000000000
--- a/lib/puppet/network/client/status.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-class Puppet::Network::Client::Status < Puppet::Network::Client::ProxyClient
- self.mkmethods
-end
-
diff --git a/lib/puppet/network/handler/ca.rb b/lib/puppet/network/handler/ca.rb
index ebb6fc427..a61f62faf 100644
--- a/lib/puppet/network/handler/ca.rb
+++ b/lib/puppet/network/handler/ca.rb
@@ -1,151 +1,61 @@
require 'openssl'
require 'puppet'
-require 'puppet/sslcertificates'
require 'xmlrpc/server'
-
-# Much of this was taken from QuickCert:
-# http://segment7.net/projects/ruby/QuickCert/
+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 autosign
- if defined?(@autosign)
- @autosign
- else
- Puppet[:autosign]
- end
- end
-
- # FIXME autosign? should probably accept both hostnames and IP addresses
- def autosign?(hostname)
- # simple values are easy
- if autosign == true or autosign == false
- return autosign
- end
-
- # we only otherwise know how to handle files
- unless autosign =~ /^\//
- raise Puppet::Error, "Invalid autosign value #{autosign.inspect}"
- end
-
- unless FileTest.exists?(autosign)
- unless defined?(@@warnedonautosign)
- @@warnedonautosign = true
- Puppet.info "Autosign is enabled but #{autosign} is missing"
- end
- return false
- end
- auth = Puppet::Network::AuthStore.new
- File.open(autosign) { |f|
- f.each { |line|
- next if line =~ /^\s*#/
- next if line =~ /^\s*$/
- auth.allow(line.chomp)
- }
- }
-
- # for now, just cheat and pass a fake IP address to allowed?
- auth.allowed?(hostname, "127.1.1.1")
- end
-
def initialize(hash = {})
Puppet.settings.use(:main, :ssl, :ca)
- @autosign = hash[:autosign] if hash.include? :autosign
- @ca = Puppet::SSLCertificates::CA.new(hash)
+ @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 = OpenSSL::X509::Request.new(csrtext)
-
- # Use the hostname from the CSR, not from the network.
- subject = csr.subject
-
- nameary = subject.to_a.find { |ary|
- ary[0] == "CN"
- }
-
- if nameary.nil?
- Puppet.err(
- "Invalid certificate request: could not retrieve server name"
- )
- return "invalid"
- end
-
- hostname = nameary[1]
+ 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.
- # save_pk(hostname, csr.public_key)
-
- certfile = File.join(Puppet[:certdir], [hostname, "pem"].join("."))
# first check to see if we already have a signed cert for the host
- cert, cacert = ca.getclientcert(hostname)
- if cert and cacert
+ 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.public_key.to_s == cert.public_key.to_s
+ 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
- return [cert.to_pem, cacert.to_pem]
- elsif @ca
- if self.autosign?(hostname) or client.nil?
- Puppet.info "Signing certificate for CA server" if client.nil?
- # okay, we don't have a signed cert
- # if we're a CA and autosign is turned on, then go ahead and sign
- # the csr and return the results
- Puppet.info "Signing certificate for #{hostname}"
- cert, cacert = @ca.sign(csr)
- #Puppet.info "Cert: #{cert.class}; Cacert: #{cacert.class}"
- return [cert.to_pem, cacert.to_pem]
- else # just write out the csr for later signing
- if @ca.getclientcsr(hostname)
- Puppet.info "Not replacing existing request from #{hostname}"
- else
- Puppet.notice "Host #{hostname} has a waiting certificate request"
- @ca.storeclientcsr(csr)
- end
- return ["", ""]
- end
+ [cert.to_s, cacert.to_s]
else
- raise "huh?"
- end
- end
+ Puppet::SSL::CertificateRequest.indirection.save(csr)
- private
-
- # Save the public key.
- def save_pk(hostname, public_key)
- pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.'))
-
- if FileTest.exists?(pkeyfile)
- currentkey = File.open(pkeyfile) { |k| k.read }
- unless currentkey == public_key.to_s
- raise Puppet::Error, "public keys for #{hostname} differ"
+ # 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
- else
- File.open(pkeyfile, "w", 0644) { |f|
- f.print public_key.to_s
- }
end
end
end
end
diff --git a/lib/puppet/network/handler/filebucket.rb b/lib/puppet/network/handler/filebucket.rb
index 55028ee64..0ca467f7a 100755
--- a/lib/puppet/network/handler/filebucket.rb
+++ b/lib/puppet/network/handler/filebucket.rb
@@ -1,51 +1,53 @@
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
index 5da4cedef..8fe3da29a 100755
--- a/lib/puppet/network/handler/fileserver.rb
+++ b/lib/puppet/network/handler/fileserver.rb
@@ -1,732 +1,732 @@
require 'puppet'
require 'puppet/network/authstore'
require 'webrick/httpstatus'
require 'cgi'
require 'delegate'
require 'sync'
-require 'xmlrpc/server'
+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
index 62aab539e..fd2bb95b4 100644
--- a/lib/puppet/network/handler/master.rb
+++ b/lib/puppet/network/handler/master.rb
@@ -1,89 +1,87 @@
require 'openssl'
require 'puppet'
-require 'puppet/sslcertificates'
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
- @ca = (hash.include?(:CA) and hash[:CA]) ? Puppet::SSLCertificates::CA.new : nil
-
# 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
index cdd6c8be4..5e3ee266d 100755
--- a/lib/puppet/network/handler/report.rb
+++ b/lib/puppet/network/handler/report.rb
@@ -1,80 +1,82 @@
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
index b02d3a548..1bc62bcd9 100755
--- a/lib/puppet/network/handler/runner.rb
+++ b/lib/puppet/network/handler/runner.rb
@@ -1,31 +1,33 @@
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
index ec6a402a6..df6215f9c 100644
--- a/lib/puppet/network/handler/status.rb
+++ b/lib/puppet/network/handler/status.rb
@@ -1,16 +1,18 @@
+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_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb
index ce0401ad2..fb9516461 100644
--- a/lib/puppet/network/http_server/mongrel.rb
+++ b/lib/puppet/network/http_server/mongrel.rb
@@ -1,130 +1,129 @@
#!/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/http_server/webrick.rb b/lib/puppet/network/http_server/webrick.rb
deleted file mode 100644
index 1f4b3b0e7..000000000
--- a/lib/puppet/network/http_server/webrick.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-require 'puppet'
-require 'webrick'
-require 'webrick/https'
-require 'fcntl'
-
-require 'puppet/sslcertificates/support'
-require 'puppet/network/xmlrpc/webrick_servlet'
-require 'puppet/network/http_server'
-require 'puppet/network/client'
-require 'puppet/network/handler'
-
-module Puppet
- class ServerError < RuntimeError; end
- module Network
- # The old-school, pure ruby webrick server, which is the default serving
- # mechanism.
- class HTTPServer::WEBrick < WEBrick::HTTPServer
- include Puppet::SSLCertificates::Support
-
- # Read the CA cert and CRL and populate an OpenSSL::X509::Store
- # with them, with flags appropriate for checking client
- # certificates for revocation
- def x509store
- unless File.exist?(Puppet[:cacrl])
- # No CRL, no store needed
- return nil
- end
- crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl]))
- store = OpenSSL::X509::Store.new
- store.purpose = OpenSSL::X509::PURPOSE_ANY
- store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
- raise Puppet::Error, "Could not find CA certificate" unless self.ca_cert
-
- store.add_file(Puppet[:localcacert])
- store.add_crl(crl)
- store
- end
-
- # Set up the http log.
- def httplog
- args = []
-
- # yuck; separate http logs
- file = nil
- Puppet.settings.use(:main, :ssl, Puppet[:name])
- if Puppet.run_mode.master?
- file = Puppet[:masterhttplog]
- else
- file = Puppet[:httplog]
- end
-
- # open the log manually to prevent file descriptor leak
- file_io = open(file, "a+")
- file_io.sync
- file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-
- args << file_io
- args << WEBrick::Log::DEBUG if Puppet[:debug]
-
- log = WEBrick::Log.new(*args)
-
-
- log
- end
-
- # Create our server, yo.
- def initialize(hash = {})
- Puppet.info "Starting server for Puppet version #{Puppet.version}"
-
- if handlers = hash[:Handlers]
- handler_instances = setup_handlers(handlers)
- else
- raise ServerError, "A server must have handlers"
- end
-
- unless self.read_cert
- if ca = handler_instances.find { |handler| handler.is_a?(Puppet::Network::Handler.ca) }
- request_cert(ca)
- else
- raise Puppet::Error, "No certificate and no CA; cannot get cert"
- end
- end
-
- setup_webrick(hash)
-
- begin
- super(hash)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not start WEBrick: #{detail}"
- end
-
- # make sure children don't inherit the sockets
- listeners.each { |sock|
- sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
- }
-
- Puppet.info "Listening on port #{hash[:Port]}"
-
- # this creates a new servlet for every connection,
- # but all servlets have the same list of handlers
- # thus, the servlets can have their own state -- passing
- # around the requests and such -- but the handlers
- # have a global state
-
- # mount has to be called after the server is initialized
- servlet = Puppet::Network::XMLRPC::WEBrickServlet.new( handler_instances)
- self.mount("/RPC2", servlet)
- end
-
- # Create a ca client to set up our cert for us.
- def request_cert(ca)
- client = Puppet::Network::Client.ca.new(:CA => ca)
- raise Puppet::Error, "Could get certificate" unless client.request_cert
- end
-
- # Create all of our handler instances.
- def setup_handlers(handlers)
- raise ServerError, "Handlers must have arguments" unless handlers.is_a?(Hash)
-
- handlers.collect { |handler, args|
- hclass = nil
- unless hclass = Puppet::Network::Handler.handler(handler)
- raise ServerError, "Invalid handler #{handler}"
- end
- hclass.new(args)
- }
- end
-
- # Handle all of the many webrick arguments.
- def setup_webrick(hash)
- hash[:Port] ||= Puppet[:masterport]
- hash[:Logger] ||= self.httplog
- hash[:AccessLog] ||= [
- [ self.httplog, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
- [ self.httplog, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
- ]
-
- hash[:SSLCertificateStore] = x509store
- hash[:SSLCertificate] = self.cert
- hash[:SSLPrivateKey] = self.key
- hash[:SSLStartImmediately] = true
- hash[:SSLEnable] = true
- hash[:SSLCACertificateFile] = Puppet[:localcacert]
- hash[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
- hash[:SSLCertName] = nil
-
- if addr = Puppet[:bindaddress] and addr != ""
- hash[:BindAddress] = addr
- end
- end
- end
- end
-end
-
diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb
deleted file mode 100644
index ca6ac60ef..000000000
--- a/lib/puppet/network/xmlrpc/client.rb
+++ /dev/null
@@ -1,211 +0,0 @@
-require 'puppet/sslcertificates'
-require 'puppet/network/http_pool'
-require 'openssl'
-require 'puppet/external/base64'
-
-require 'xmlrpc/client'
-require 'net/https'
-require 'yaml'
-
-module Puppet::Network
- class ClientError < Puppet::Error; end
- class XMLRPCClientError < Puppet::Error; end
- class XMLRPCClient < ::XMLRPC::Client
-
- attr_accessor :puppet_server, :puppet_port
- @clients = {}
-
- class << self
- include Puppet::Util
- include Puppet::Util::ClassGen
- end
-
- # Create a netclient for each handler
- def self.mkclient(handler)
- interface = handler.interface
- namespace = interface.prefix
-
- # Create a subclass for every client type. This is
- # so that all of the methods are on their own class,
- # so that their namespaces can define the same methods if
- # they want.
- constant = handler.name.to_s.capitalize
- name = namespace.downcase
- newclient = genclass(name, :hash => @clients, :constant => constant)
-
- interface.methods.each { |ary|
- method = ary[0]
- newclient.send(:define_method,method) { |*args|
- make_rpc_call(namespace, method, *args)
- }
- }
-
- newclient
- end
-
- def self.handler_class(handler)
- @clients[handler] || self.mkclient(handler)
- end
-
- class ErrorHandler
- def initialize(&block)
- singleton_class.define_method(:execute, &block)
- end
- end
-
- # Use a class variable so all subclasses have access to it.
- @@error_handlers = {}
-
- def self.error_handler(exception)
- if handler = @@error_handlers[exception.class]
- return handler
- else
- return @@error_handlers[:default]
- end
- end
-
- def self.handle_error(*exceptions, &block)
- handler = ErrorHandler.new(&block)
-
- exceptions.each do |exception|
- @@error_handlers[exception] = handler
- end
- end
-
- handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
- if detail.message =~ /bad write retry/
- Puppet.warning "Transient SSL write error; restarting connection and retrying"
- client.recycle_connection
- return :retry
- end
- ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
- Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
- end
- raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
- end
-
- handle_error(:default) do |client, detail, namespace, method|
- if detail.message.to_s =~ /^Wrong size\. Was \d+, should be \d+$/
- Puppet.warning "XMLRPC returned wrong size. Retrying."
- return :retry
- end
- Puppet.err "Could not call #{namespace}.#{method}: #{detail.inspect}"
- error = XMLRPCClientError.new(detail.to_s)
- error.set_backtrace detail.backtrace
- raise error
- end
-
- handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
- if detail.message =~ /bad write retry/
- Puppet.warning "Transient SSL write error; restarting connection and retrying"
- client.recycle_connection
- return :retry
- end
- ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
- Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
- end
- raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
- end
-
- handle_error(::XMLRPC::FaultException) do |client, detail, namespace, method|
- raise XMLRPCClientError, detail.faultString
- end
-
- handle_error(Errno::ECONNREFUSED) do |client, detail, namespace, method|
- msg = "Could not connect to #{client.host} on port #{client.port}"
- raise XMLRPCClientError, msg
- end
-
- handle_error(SocketError) do |client, detail, namespace, method|
- Puppet.err "Could not find server #{@host}: #{detail}"
- error = XMLRPCClientError.new("Could not find server #{client.host}")
- error.set_backtrace detail.backtrace
- raise error
- end
-
- handle_error(Errno::EPIPE, EOFError) do |client, detail, namespace, method|
- Puppet.info "Other end went away; restarting connection and retrying"
- client.recycle_connection
- return :retry
- end
-
- handle_error(Timeout::Error) do |client, detail, namespace, method|
- Puppet.err "Connection timeout calling #{namespace}.#{method}: #{detail}"
- error = XMLRPCClientError.new("Connection Timeout")
- error.set_backtrace(detail.backtrace)
- raise error
- end
-
- def make_rpc_call(namespace, method, *args)
- Puppet.debug "Calling #{namespace}.#{method}"
- begin
- call("#{namespace}.#{method}",*args)
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- retry if self.class.error_handler(detail).execute(self, detail, namespace, method) == :retry
- end
- ensure
- http.finish if http.started?
- end
-
- def http
- @http ||= Puppet::Network::HttpPool.http_instance(host, port, true)
- end
-
- attr_reader :host, :port
-
- def initialize(hash = {})
- hash[:Path] ||= "/RPC2"
- hash[:Server] ||= Puppet[:server]
- hash[:Port] ||= Puppet[:masterport]
- hash[:HTTPProxyHost] ||= Puppet[:http_proxy_host]
- hash[:HTTPProxyPort] ||= Puppet[:http_proxy_port]
-
- if "none" == hash[:HTTPProxyHost]
- hash[:HTTPProxyHost] = nil
- hash[:HTTPProxyPort] = nil
- end
-
-
- super(
-
- hash[:Server],
- hash[:Path],
- hash[:Port],
- hash[:HTTPProxyHost],
- hash[:HTTPProxyPort],
-
- nil, # user
- nil, # password
- true, # use_ssl
- Puppet[:configtimeout] # use configured timeout (#1176)
- )
- @http = Puppet::Network::HttpPool.http_instance(@host, @port)
- end
-
- # Get rid of our existing connection, replacing it with a new one.
- # This should only happen if we lose our connection somehow (e.g., an EPIPE)
- # or we've just downloaded certs and we need to create new http instances
- # with the certs added.
- def recycle_connection
- http.finish if http.started?
- @http = nil
- self.http # force a new one
- end
-
- def start
- @http.start unless @http.started?
- rescue => detail
- Puppet.err "Could not connect to server: #{detail}"
- end
-
- def local
- false
- end
-
- def local?
- false
- end
- end
-end
diff --git a/lib/puppet/provider/exec/windows.rb b/lib/puppet/provider/exec/windows.rb
index 9ce29f12b..76ca1b360 100644
--- a/lib/puppet/provider/exec/windows.rb
+++ b/lib/puppet/provider/exec/windows.rb
@@ -1,35 +1,34 @@
require 'puppet/provider/exec'
Puppet::Type.type(:exec).provide :windows, :parent => Puppet::Provider::Exec do
include Puppet::Util::Execution
- confine :feature => :microsoft_windows
- defaultfor :feature => :microsoft_windows
+ confine :operatingsystem => :windows
+ defaultfor :operatingsystem => :windows
desc "Execute external binaries directly, on Windows systems.
This does not pass through a shell, or perform any interpolation, but
only directly calls the command with the arguments given."
# Verify that we have the executable
def checkexe(command)
exe = extractexe(command)
if absolute_path?(exe)
if !File.exists?(exe)
raise ArgumentError, "Could not find command '#{exe}'"
elsif !File.file?(exe)
raise ArgumentError, "'#{exe}' is a #{File.ftype(exe)}, not a file"
end
return
end
- path = resource[:path] || []
-
- exts = [".exe", ".ps1", ".bat", ".com", ""]
- withenv :PATH => path.join(File::PATH_SEPARATOR) do
- return if exts.any? {|ext| which(exe + ext) }
+ if resource[:path]
+ withenv :PATH => resource[:path].join(File::PATH_SEPARATOR) do
+ return if which(exe)
+ end
end
raise ArgumentError, "Could not find command '#{exe}'"
end
end
diff --git a/lib/puppet/provider/file/windows.rb b/lib/puppet/provider/file/windows.rb
index d71e7d43c..5a7b9adf5 100644
--- a/lib/puppet/provider/file/windows.rb
+++ b/lib/puppet/provider/file/windows.rb
@@ -1,100 +1,100 @@
Puppet::Type.type(:file).provide :windows do
desc "Uses Microsoft Windows functionality to manage file's users and rights."
- confine :feature => :microsoft_windows
+ confine :operatingsystem => :windows
include Puppet::Util::Warnings
if Puppet.features.microsoft_windows?
require 'puppet/util/windows'
require 'puppet/util/adsi'
include Puppet::Util::Windows::Security
end
ERROR_INVALID_SID_STRUCTURE = 1337
def id2name(id)
# If it's a valid sid, get the name. Otherwise, it's already a name, so
# just return it.
begin
if string_to_sid_ptr(id)
name = nil
Puppet::Util::ADSI.execquery(
"SELECT Name FROM Win32_Account WHERE SID = '#{id}'
AND LocalAccount = true"
).each { |a| name ||= a.name }
return name
end
rescue Puppet::Util::Windows::Error => e
raise unless e.code == ERROR_INVALID_SID_STRUCTURE
end
id
end
# Determine if the account is valid, and if so, return the UID
def name2id(value)
# If it's a valid sid, then return it. Else, it's a name we need to convert
# to sid.
begin
return value if string_to_sid_ptr(value)
rescue Puppet::Util::Windows::Error => e
raise unless e.code == ERROR_INVALID_SID_STRUCTURE
end
Puppet::Util::ADSI.sid_for_account(value) rescue nil
end
# We use users and groups interchangeably, so use the same methods for both
# (the type expects different methods, so we have to oblige).
alias :uid2name :id2name
alias :gid2name :id2name
alias :name2gid :name2id
alias :name2uid :name2id
def owner
return :absent unless resource.exist?
get_owner(resource[:path])
end
def owner=(should)
begin
set_owner(should, resource[:path])
rescue => detail
raise Puppet::Error, "Failed to set owner to '#{should}': #{detail}"
end
end
def group
return :absent unless resource.exist?
get_group(resource[:path])
end
def group=(should)
begin
set_group(should, resource[:path])
rescue => detail
raise Puppet::Error, "Failed to set group to '#{should}': #{detail}"
end
end
def mode
if resource.exist?
get_mode(resource[:path]).to_s(8)
else
:absent
end
end
def mode=(value)
begin
set_mode(value.to_i(8), resource[:path])
rescue => detail
error = Puppet::Error.new("failed to set mode #{mode} on #{resource[:path]}: #{detail.message}")
error.set_backtrace detail.backtrace
raise error
end
:file_changed
end
end
diff --git a/lib/puppet/provider/group/aix.rb b/lib/puppet/provider/group/aix.rb
index ecdef6070..a7ae72cf0 100755
--- a/lib/puppet/provider/group/aix.rb
+++ b/lib/puppet/provider/group/aix.rb
@@ -1,141 +1,141 @@
#
# Group Puppet provider for AIX. It uses standard commands to manage groups:
# mkgroup, rmgroup, lsgroup, chgroup
#
# Author:: Hector Rivas Gandara <keymon@gmail.com>
-#
+#
require 'puppet/provider/aixobject'
Puppet::Type.type(:group).provide :aix, :parent => Puppet::Provider::AixObject do
- desc "Group management for AIX! Users are managed with mkgroup, rmgroup, lsgroup, chgroup"
+ desc "Group management for AIX."
# This will the the default provider for this platform
defaultfor :operatingsystem => :aix
confine :operatingsystem => :aix
# Provider features
has_features :manages_aix_lam
has_features :manages_members
# Commands that manage the element
commands :list => "/usr/sbin/lsgroup"
commands :add => "/usr/bin/mkgroup"
commands :delete => "/usr/sbin/rmgroup"
commands :modify => "/usr/bin/chgroup"
# Group attributes to ignore
def self.attribute_ignore
[]
end
# AIX attributes to properties mapping.
- #
+ #
# Valid attributes to be managed by this provider.
# It is a list with of hash
# :aix_attr AIX command attribute name
# :puppet_prop Puppet propertie name
# :to Method to adapt puppet property to aix command value. Optional.
# :from Method to adapt aix command value to puppet property. Optional
self.attribute_mapping = [
#:name => :name,
{:aix_attr => :id, :puppet_prop => :gid },
{:aix_attr => :users, :puppet_prop => :members,
:from => :users_from_attr},
{:aix_attr => :attributes, :puppet_prop => :attributes},
]
-
+
#--------------
# Command definition
-
+
# Return the IA module arguments based on the resource param ia_load_module
def get_ia_module_args
if @resource[:ia_load_module]
["-R", @resource[:ia_load_module].to_s]
else
[]
end
end
-
+
def lscmd(value=@resource[:name])
[self.class.command(:list)] +
self.get_ia_module_args +
[ value]
end
def lsallcmd()
lscmd("ALL")
end
def addcmd(extra_attrs = [])
# Here we use the @resource.to_hash to get the list of provided parameters
# Puppet does not call to self.<parameter>= method if it does not exists.
#
# It gets an extra list of arguments to add to the user.
[self.class.command(:add) ] +
self.get_ia_module_args +
self.hash2args(@resource.to_hash) +
extra_attrs + [@resource[:name]]
end
def modifycmd(hash = property_hash)
args = self.hash2args(hash)
return nil if args.empty?
-
+
[self.class.command(:modify)] +
self.get_ia_module_args +
args + [@resource[:name]]
end
def deletecmd
[self.class.command(:delete)] +
self.get_ia_module_args +
[@resource[:name]]
end
#--------------
# Overwrite get_arguments to add the attributes arguments
def get_arguments(key, value, mapping, objectinfo)
# In the case of attributes, return a list of key=vlaue
if key == :attributes
raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \
unless value and value.is_a? Hash
return value.select { |k,v| true }.map { |pair| pair.join("=") }
end
super(key, value, mapping, objectinfo)
end
def filter_attributes(hash)
# Return only not managed attributtes.
hash.select {
|k,v| !self.class.attribute_mapping_from.include?(k) and
!self.class.attribute_ignore.include?(k)
}.inject({}) {
|hash, array| hash[array[0]] = array[1]; hash
}
end
def attributes
filter_attributes(getosinfo(refresh = false))
end
def attributes=(attr_hash)
#self.class.validate(param, value)
param = :attributes
cmd = modifycmd({param => filter_attributes(attr_hash)})
- if cmd
+ if cmd
begin
execute(cmd)
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
end
end
end
# Force convert users it a list.
def users_from_attr(value)
(value.is_a? String) ? value.split(',') : value
end
end
diff --git a/lib/puppet/provider/group/groupadd.rb b/lib/puppet/provider/group/groupadd.rb
index bcc08d9f7..ecbfb28b3 100644
--- a/lib/puppet/provider/group/groupadd.rb
+++ b/lib/puppet/provider/group/groupadd.rb
@@ -1,32 +1,30 @@
require 'puppet/provider/nameservice/objectadd'
Puppet::Type.type(:group).provide :groupadd, :parent => Puppet::Provider::NameService::ObjectAdd do
- desc "Group management via `groupadd` and its ilk.
-
- The default for most platforms
+ desc "Group management via `groupadd` and its ilk. The default for most platforms.
"
commands :add => "groupadd", :delete => "groupdel", :modify => "groupmod"
has_feature :system_groups
verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
end
def addcmd
cmd = [command(:add)]
if gid = @resource.should(:gid)
unless gid == :absent
cmd << flag(:gid) << gid
end
end
cmd << "-o" if @resource.allowdupe?
cmd << "-r" if @resource.system?
cmd << @resource[:name]
cmd
end
end
diff --git a/lib/puppet/provider/group/ldap.rb b/lib/puppet/provider/group/ldap.rb
index 86c72a5d3..78333f176 100644
--- a/lib/puppet/provider/group/ldap.rb
+++ b/lib/puppet/provider/group/ldap.rb
@@ -1,47 +1,45 @@
require 'puppet/provider/ldap'
Puppet::Type.type(:group).provide :ldap, :parent => Puppet::Provider::Ldap do
- desc "Group management via `ldap`.
+ desc "Group management via LDAP.
- This provider requires that you have valid values for all of the
- ldap-related settings, including `ldapbase`. You will also almost
- definitely need settings for `ldapuser` and `ldappassword`, so that
- your clients can write to ldap.
+ This provider requires that you have valid values for all of the
+ LDAP-related settings in `puppet.conf`, including `ldapbase`. You will
+ almost definitely need settings for `ldapuser` and `ldappassword` in order
+ for your clients to write to LDAP.
- Note that this provider will automatically generate a GID for you if you do
- not specify one, but it is a potentially expensive operation, as it
- iterates across all existing groups to pick the appropriate next one.
-
- "
+ Note that this provider will automatically generate a GID for you if you do
+ not specify one, but it is a potentially expensive operation, as it
+ iterates across all existing groups to pick the appropriate next one."
confine :true => Puppet.features.ldap?, :false => (Puppet[:ldapuser] == "")
# We're mapping 'members' here because we want to make it
# easy for the ldap user provider to manage groups. This
# way it can just use the 'update' method in the group manager,
# whereas otherwise it would need to replicate that code.
manages(:posixGroup).at("ou=Groups").and.maps :name => :cn, :gid => :gidNumber, :members => :memberUid
# Find the next gid after the current largest gid.
provider = self
manager.generates(:gidNumber).with do
largest = 500
if existing = provider.manager.search
existing.each do |hash|
next unless value = hash[:gid]
num = value[0].to_i
largest = num if num > largest
end
end
largest + 1
end
# Convert a group name to an id.
def self.name2id(group)
return nil unless result = manager.search("cn=#{group}") and result.length > 0
# Only use the first result.
group = result[0]
gid = group[:gid][0]
end
end
diff --git a/lib/puppet/provider/group/windows_adsi.rb b/lib/puppet/provider/group/windows_adsi.rb
index 4ddc83bc1..83dd00b29 100644
--- a/lib/puppet/provider/group/windows_adsi.rb
+++ b/lib/puppet/provider/group/windows_adsi.rb
@@ -1,55 +1,54 @@
require 'puppet/util/adsi'
Puppet::Type.type(:group).provide :windows_adsi do
desc "Group management for Windows"
defaultfor :operatingsystem => :windows
- confine :operatingsystem => :windows
- confine :feature => :microsoft_windows
+ confine :operatingsystem => :windows
has_features :manages_members
def group
@group ||= Puppet::Util::ADSI::Group.new(@resource[:name])
end
def members
group.members
end
def members=(members)
group.set_members(members)
end
def create
@group = Puppet::Util::ADSI::Group.create(@resource[:name])
@group.commit
self.members = @resource[:members]
end
def exists?
Puppet::Util::ADSI::Group.exists?(@resource[:name])
end
def delete
Puppet::Util::ADSI::Group.delete(@resource[:name])
end
# Only flush if we created or modified a group, not deleted
def flush
@group.commit if @group
end
def gid
Puppet::Util::ADSI.sid_for_account(@resource[:name])
end
def gid=(value)
fail "gid is read-only"
end
def self.instances
Puppet::Util::ADSI::Group.map { |g| new(:ensure => :present, :name => g.name) }
end
end
diff --git a/lib/puppet/provider/package/aix.rb b/lib/puppet/provider/package/aix.rb
index 134a84526..088099d45 100644
--- a/lib/puppet/provider/package/aix.rb
+++ b/lib/puppet/provider/package/aix.rb
@@ -1,128 +1,128 @@
require 'puppet/provider/package'
require 'puppet/util/package'
Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package do
- desc "Installation from AIX Software directory"
+ desc "Installation from the AIX software directory."
# The commands we are using on an AIX box are installed standard
# (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
commands :lslpp => "/usr/bin/lslpp",
:installp => "/usr/sbin/installp"
# AIX supports versionable packages with and without a NIM server
has_feature :versionable
confine :operatingsystem => [ :aix ]
defaultfor :operatingsystem => :aix
attr_accessor :latest_info
def self.srclistcmd(source)
[ command(:installp), "-L", "-d", source ]
end
def self.prefetch(packages)
raise Puppet::Error, "The aix provider can only be used by root" if Process.euid != 0
return unless packages.detect { |name, package| package.should(:ensure) == :latest }
sources = packages.collect { |name, package| package[:source] }.uniq
updates = {}
sources.each do |source|
execute(self.srclistcmd(source)).each do |line|
if line =~ /^[^#][^:]*:([^:]*):([^:]*)/
current = {}
current[:name] = $1
current[:version] = $2
current[:source] = source
if updates.key?(current[:name])
previous = updates[current[:name]]
updates[ current[:name] ] = current unless Puppet::Util::Package.versioncmp(previous[:version], current[:version]) == 1
else
updates[current[:name]] = current
end
end
end
end
packages.each do |name, package|
if info = updates[package[:name]]
package.provider.latest_info = info[0]
end
end
end
def uninstall
# Automatically process dependencies when installing/uninstalling
# with the -g option to installp.
installp "-gu", @resource[:name]
end
def install(useversion = true)
unless source = @resource[:source]
self.fail "A directory is required which will be used to find packages"
end
pkg = @resource[:name]
pkg << " #{@resource.should(:ensure)}" if (! @resource.should(:ensure).is_a? Symbol) and useversion
installp "-acgwXY", "-d", source, pkg
end
def self.pkglist(hash = {})
cmd = [command(:lslpp), "-qLc"]
if name = hash[:pkgname]
cmd << name
end
begin
list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*)/).collect { |n,e|
{ :name => n, :ensure => e, :provider => self.name }
}
rescue Puppet::ExecutionFailure => detail
if hash[:pkgname]
return nil
else
raise Puppet::Error, "Could not list installed Packages: #{detail}"
end
end
if hash[:pkgname]
return list.shift
else
return list
end
end
def self.instances
pkglist.collect do |hash|
new(hash)
end
end
def latest
upd = latest_info
unless upd.nil?
return "#{upd[:version]}"
else
raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent
return properties[:ensure]
end
end
def query
self.class.pkglist(:pkgname => @resource[:name])
end
def update
self.install(false)
end
end
diff --git a/lib/puppet/provider/package/macports.rb b/lib/puppet/provider/package/macports.rb
index 6e5526647..22fe6d930 100755
--- a/lib/puppet/provider/package/macports.rb
+++ b/lib/puppet/provider/package/macports.rb
@@ -1,105 +1,105 @@
require 'puppet/provider/package'
Puppet::Type.type(:package).provide :macports, :parent => Puppet::Provider::Package do
desc "Package management using MacPorts on OS X.
Supports MacPorts versions and revisions, but not variants.
- Variant preferences may be specified using the MacPorts variants.conf file
- http://guide.macports.org/chunked/internals.configuration-files.html#internals.configuration-files.variants-conf
+ Variant preferences may be specified using
+ [the MacPorts variants.conf file](http://guide.macports.org/chunked/internals.configuration-files.html#internals.configuration-files.variants-conf).
- When specifying a version in the Puppet DSL, only specify the version, not the revision
+ When specifying a version in the Puppet DSL, only specify the version, not the revision.
Revisions are only used internally for ensuring the latest version/revision of a port.
"
confine :operatingsystem => :darwin
commands :port => "/opt/local/bin/port"
has_feature :installable
has_feature :uninstallable
has_feature :upgradeable
has_feature :versionable
def self.parse_installed_query_line(line)
regex = /(\S+)\s+@(\S+)_(\S+)\s+\(active\)/
fields = [:name, :ensure, :revision]
hash_from_line(line, regex, fields)
end
def self.parse_info_query_line(line)
regex = /(\S+)\s+(\S+)/
fields = [:version, :revision]
hash_from_line(line, regex, fields)
end
def self.hash_from_line(line, regex, fields)
hash = {}
if match = regex.match(line)
fields.zip(match.captures) { |field, value|
hash[field] = value
}
hash[:provider] = self.name
return hash
end
nil
end
def self.instances
packages = []
port("-q", :installed).each do |line|
if hash = parse_installed_query_line(line)
packages << new(hash)
end
end
packages
end
def install
should = @resource.should(:ensure)
if [:latest, :installed, :present].include?(should)
output = port("-q", :install, @resource[:name])
else
output = port("-q", :install, @resource[:name], "@#{should}")
end
# MacPorts now correctly exits non-zero with appropriate errors in
# situations where a port cannot be found or installed.
end
def query
return self.class.parse_installed_query_line(port("-q", :installed, @resource[:name]))
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])
return nil if info_line == ""
if newest = self.class.parse_info_query_line(info_line)
current = query
# We're doing some fiddling behind the scenes here to cope with updated revisions.
# If we're already at the latest version/revision, then just return the version
# so the current and desired values match. Otherwise return version and revision
# to trigger an upgrade to the latest revision.
if newest[:version] == current[:ensure] and newest[:revision] == current[:revision]
return current[:ensure]
else
return "#{newest[:version]}_#{newest[:revision]}"
end
end
nil
end
def uninstall
port("-q", :uninstall, @resource[:name])
end
def update
if query[:name] == @resource[:name] # 'port upgrade' cannot install new ports
port("-q", :upgrade, @resource[:name])
else
install
end
end
end
diff --git a/lib/puppet/provider/package/nim.rb b/lib/puppet/provider/package/nim.rb
index 8f52016db..49d3c8b30 100644
--- a/lib/puppet/provider/package/nim.rb
+++ b/lib/puppet/provider/package/nim.rb
@@ -1,35 +1,35 @@
require 'puppet/provider/package'
require 'puppet/util/package'
Puppet::Type.type(:package).provide :nim, :parent => :aix, :source => :aix do
- desc "Installation from NIM LPP source"
+ desc "Installation from NIM LPP source."
# The commands we are using on an AIX box are installed standard
# (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
commands :nimclient => "/usr/sbin/nimclient"
# If NIM has not been configured, /etc/niminfo will not be present.
# However, we have no way of knowing if the NIM server is not configured
# properly.
confine :exists => "/etc/niminfo"
has_feature :versionable
attr_accessor :latest_info
def self.srclistcmd(source)
[ command(:nimclient), "-o", "showres", "-a", "installp_flags=L", "-a", "resource=#{source}" ]
end
def install(useversion = true)
unless source = @resource[:source]
self.fail "An LPP source location is required in 'source'"
end
pkg = @resource[:name]
pkg << " " << @resource.should(:ensure) if (! @resource.should(:ensure).is_a? Symbol) and useversion
nimclient "-o", "cust", "-a", "installp_flags=acgwXY", "-a", "lpp_source=#{source}", "-a", "filesets='#{pkg}'"
end
end
diff --git a/lib/puppet/provider/package/pkgdmg.rb b/lib/puppet/provider/package/pkgdmg.rb
index b24514c44..4bdb2d38a 100644
--- a/lib/puppet/provider/package/pkgdmg.rb
+++ b/lib/puppet/provider/package/pkgdmg.rb
@@ -1,129 +1,129 @@
#
# Motivation: DMG files provide a true HFS file system
# and are easier to manage and .pkg bundles.
#
# Note: the 'apple' Provider checks for the package name
# in /L/Receipts. Since we install multiple pkg's from a single
# source, we treat the source .pkg.dmg file as the package name.
# As a result, we store installed .pkg.dmg file names
# in /var/db/.puppet_pkgdmg_installed_<name>
require 'puppet/provider/package'
require 'facter/util/plist'
Puppet::Type.type(:package).provide :pkgdmg, :parent => Puppet::Provider::Package do
desc "Package management based on Apple's Installer.app and
DiskUtility.app. This package works by checking the contents of a
DMG image for Apple pkg or mpkg files. Any number of pkg or mpkg
- files may exist in the root directory of the DMG file system. Sub
- directories are not checked for packages. See `the wiki docs
- <http://projects.puppetlabs.com/projects/puppet/wiki/Package_Management_With_Dmg_Patterns>`
+ files may exist in the root directory of the DMG file system.
+ Subdirectories are not checked for packages. See
+ [the wiki docs on this provider](http://projects.puppetlabs.com/projects/puppet/wiki/Package_Management_With_Dmg_Patterns)
for more detail."
confine :operatingsystem => :darwin
defaultfor :operatingsystem => :darwin
commands :installer => "/usr/sbin/installer"
commands :hdiutil => "/usr/bin/hdiutil"
commands :curl => "/usr/bin/curl"
# JJM We store a cookie for each installed .pkg.dmg in /var/db
def self.instance_by_name
Dir.entries("/var/db").find_all { |f|
f =~ /^\.puppet_pkgdmg_installed_/
}.collect do |f|
name = f.sub(/^\.puppet_pkgdmg_installed_/, '')
yield name if block_given?
name
end
end
def self.instances
instance_by_name.collect do |name|
new(
:name => name,
:provider => :pkgdmg,
:ensure => :installed
)
end
end
def self.installpkg(source, name, orig_source)
installer "-pkg", source, "-target", "/"
# Non-zero exit status will throw an exception.
File.open("/var/db/.puppet_pkgdmg_installed_#{name}", "w") do |t|
t.print "name: '#{name}'\n"
t.print "source: '#{orig_source}'\n"
end
end
def self.installpkgdmg(source, name)
unless source =~ /\.dmg$/i || source =~ /\.pkg$/i
raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file")
end
require 'open-uri'
cached_source = source
if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
cached_source = "/tmp/#{name}"
begin
curl "-o", cached_source, "-C", "-", "-k", "-s", "--url", source
Puppet.debug "Success: curl transfered [#{name}]"
rescue Puppet::ExecutionFailure
Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods."
cached_source = source
end
end
begin
if source =~ /\.dmg$/i
File.open(cached_source) do |dmg|
xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", dmg.path
hdiutil_info = Plist::parse_xml(xml_str)
raise Puppet::Error.new("No disk entities returned by mount at #{dmg.path}") unless hdiutil_info.has_key?("system-entities")
mounts = hdiutil_info["system-entities"].collect { |entity|
entity["mount-point"]
}.compact
begin
mounts.each do |mountpoint|
Dir.entries(mountpoint).select { |f|
f =~ /\.m{0,1}pkg$/i
}.each do |pkg|
installpkg("#{mountpoint}/#{pkg}", name, source)
end
end
ensure
mounts.each do |mountpoint|
hdiutil "eject", mountpoint
end
end
end
elsif source =~ /\.pkg$/i
installpkg(cached_source, name, source)
else
raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file")
end
ensure
# JJM Remove the file if open-uri didn't already do so.
File.unlink(cached_source) if File.exist?(cached_source)
end
end
def query
if FileTest.exists?("/var/db/.puppet_pkgdmg_installed_#{@resource[:name]}")
Puppet.debug "/var/db/.puppet_pkgdmg_installed_#{@resource[:name]} found"
return {:name => @resource[:name], :ensure => :present}
else
return nil
end
end
def install
source = nil
unless source = @resource[:source]
raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package source.")
end
unless name = @resource[:name]
raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package name.")
end
self.class.installpkgdmg(source,name)
end
end
diff --git a/lib/puppet/provider/package/ports.rb b/lib/puppet/provider/package/ports.rb
index 6a8d6a77b..62c65c8b8 100755
--- a/lib/puppet/provider/package/ports.rb
+++ b/lib/puppet/provider/package/ports.rb
@@ -1,94 +1,94 @@
Puppet::Type.type(:package).provide :ports, :parent => :freebsd, :source => :freebsd do
- desc "Support for FreeBSD's ports. Again, this still mixes packages and ports."
+ desc "Support for FreeBSD's ports. Note that this, too, mixes packages and ports."
commands :portupgrade => "/usr/local/sbin/portupgrade",
:portversion => "/usr/local/sbin/portversion",
:portuninstall => "/usr/local/sbin/pkg_deinstall",
:portinfo => "/usr/sbin/pkg_info"
defaultfor :operatingsystem => :freebsd
# I hate ports
%w{INTERACTIVE UNAME}.each do |var|
ENV.delete(var) if ENV.include?(var)
end
def install
# -N: install if the package is missing, otherwise upgrade
# -M: yes, we're a batch, so don't ask any questions
cmd = %w{-N -M BATCH=yes} << @resource[:name]
output = portupgrade(*cmd)
if output =~ /\*\* No such /
raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
end
end
# If there are multiple packages, we only use the last one
def latest
cmd = ["-v", @resource[:name]]
begin
output = portversion(*cmd)
rescue Puppet::ExecutionFailure
raise Puppet::Error.new(output)
end
line = output.split("\n").pop
unless line =~ /^(\S+)\s+(\S)\s+(.+)$/
# There's no "latest" version, so just return a placeholder
return :latest
end
pkgstuff = $1
match = $2
info = $3
unless pkgstuff =~ /^(\S+)-([^-\s]+)$/
raise Puppet::Error,
"Could not match package info '#{pkgstuff}'"
end
name, version = $1, $2
if match == "=" or match == ">"
# we're up to date or more recent
return version
end
# Else, we need to be updated; we need to pull out the new version
unless info =~ /\((\w+) has (.+)\)/
raise Puppet::Error,
"Could not match version info '#{info}'"
end
source, newversion = $1, $2
debug "Newer version in #{source}"
newversion
end
def query
# support portorigin_glob such as "mail/postfix"
name = self.name
if name =~ /\//
name = self.name.split(/\//).slice(1)
end
self.class.instances.each do |instance|
if instance.name == name
return instance.properties
end
end
nil
end
def uninstall
portuninstall @resource[:name]
end
def update
install
end
end
diff --git a/lib/puppet/provider/service/base.rb b/lib/puppet/provider/service/base.rb
index 211e7f964..380bd5944 100755
--- a/lib/puppet/provider/service/base.rb
+++ b/lib/puppet/provider/service/base.rb
@@ -1,144 +1,144 @@
Puppet::Type.type(:service).provide :base do
desc "The simplest form of service support.
You have to specify enough about your service for this to work; the
minimum you can specify is a binary for starting the process, and this
same binary will be searched for in the process table to stop the
- service. It is preferable to specify start, stop, and status commands,
- akin to how you would do so using `init`.
+ service. As with `init`-style services, it is preferable to specify start,
+ stop, and status commands.
"
commands :kill => "kill"
def self.instances
[]
end
# Get the process ID for a running process. Requires the 'pattern'
# parameter.
def getpid
@resource.fail "Either stop/status commands or a pattern must be specified" unless @resource[:pattern]
ps = Facter["ps"].value
@resource.fail "You must upgrade Facter to a version that includes 'ps'" unless ps and ps != ""
regex = Regexp.new(@resource[:pattern])
self.debug "Executing '#{ps}'"
IO.popen(ps) { |table|
table.each { |line|
if regex.match(line)
ary = line.sub(/^\s+/, '').split(/\s+/)
return ary[1]
end
}
}
nil
end
# How to restart the process.
def restart
if @resource[:restart] or restartcmd
ucommand(:restart)
else
self.stop
self.start
end
end
# There is no default command, which causes other methods to be used
def restartcmd
end
# Check if the process is running. Prefer the 'status' parameter,
# then 'statuscmd' method, then look in the process table. We give
# the object the option to not return a status command, which might
# happen if, for instance, it has an init script (and thus responds to
# 'statuscmd') but does not have 'hasstatus' enabled.
def status
if @resource[:status] or statuscmd
# Don't fail when the exit status is not 0.
ucommand(:status, false)
# Expicitly calling exitstatus to facilitate testing
if $CHILD_STATUS.exitstatus == 0
return :running
else
return :stopped
end
elsif pid = self.getpid
self.debug "PID is #{pid}"
return :running
else
return :stopped
end
end
# There is no default command, which causes other methods to be used
def statuscmd
end
# Run the 'start' parameter command, or the specified 'startcmd'.
def start
ucommand(:start)
end
# The command used to start. Generated if the 'binary' argument
# is passed.
def startcmd
if @resource[:binary]
return @resource[:binary]
else
raise Puppet::Error,
"Services must specify a start command or a binary"
end
end
# Stop the service. If a 'stop' parameter is specified, it
# takes precedence; otherwise checks if the object responds to
# a 'stopcmd' method, and if so runs that; otherwise, looks
# for the process in the process table.
# This method will generally not be overridden by submodules.
def stop
if @resource[:stop] or stopcmd
ucommand(:stop)
else
pid = getpid
unless pid
self.info "#{self.name} is not running"
return false
end
begin
output = kill pid
rescue Puppet::ExecutionFailure => detail
@resource.fail "Could not kill #{self.name}, PID #{pid}: #{output}"
end
return true
end
end
# There is no default command, which causes other methods to be used
def stopcmd
end
# A simple wrapper so execution failures are a bit more informative.
def texecute(type, command, fof = true)
begin
# #565: Services generally produce no output, so squelch them.
execute(command, :failonfail => fof, :squelch => true)
rescue Puppet::ExecutionFailure => detail
@resource.fail "Could not #{type} #{@resource.ref}: #{detail}"
end
nil
end
# Use either a specified command or the default for our provider.
def ucommand(type, fof = true)
if c = @resource[type]
cmd = [c]
else
cmd = [send("#{type}cmd")].flatten
end
texecute(type, cmd, fof)
end
end
diff --git a/lib/puppet/provider/service/bsd.rb b/lib/puppet/provider/service/bsd.rb
index e2a0e35f7..0c019fdd0 100644
--- a/lib/puppet/provider/service/bsd.rb
+++ b/lib/puppet/provider/service/bsd.rb
@@ -1,48 +1,49 @@
# Manage FreeBSD services.
Puppet::Type.type(:service).provide :bsd, :parent => :init do
- desc "FreeBSD's (and probably NetBSD?) form of `init`-style service management.
+ desc <<-EOT
+ FreeBSD's (and probably NetBSD's?) form of `init`-style service management.
- Uses `rc.conf.d` for service enabling and disabling.
+ Uses `rc.conf.d` for service enabling and disabling.
-"
+ EOT
confine :operatingsystem => [:freebsd, :netbsd, :openbsd]
@@rcconf_dir = '/etc/rc.conf.d'
def self.defpath
superclass.defpath
end
# remove service file from rc.conf.d to disable it
def disable
rcfile = File.join(@@rcconf_dir, @model[:name])
File.delete(rcfile) if File.exists?(rcfile)
end
# if the service file exists in rc.conf.d then it's already enabled
def enabled?
rcfile = File.join(@@rcconf_dir, @model[:name])
return :true if File.exists?(rcfile)
:false
end
# enable service by creating a service file under rc.conf.d with the
# proper contents
def enable
Dir.mkdir(@@rcconf_dir) if not File.exists?(@@rcconf_dir)
rcfile = File.join(@@rcconf_dir, @model[:name])
open(rcfile, 'w') { |f| f << "%s_enable=\"YES\"\n" % @model[:name] }
end
# Override stop/start commands to use one<cmd>'s and the avoid race condition
# where provider trys to stop/start the service before it is enabled
def startcmd
[self.initscript, :onestart]
end
def stopcmd
[self.initscript, :onestop]
end
end
diff --git a/lib/puppet/provider/service/daemontools.rb b/lib/puppet/provider/service/daemontools.rb
index f5a073329..bb94c43f5 100644
--- a/lib/puppet/provider/service/daemontools.rb
+++ b/lib/puppet/provider/service/daemontools.rb
@@ -1,194 +1,194 @@
# Daemontools service management
#
# author Brice Figureau <brice-puppet@daysofwonder.com>
Puppet::Type.type(:service).provide :daemontools, :parent => :base do
- desc "Daemontools service management.
+ desc <<-EOT
+ Daemontools service management.
- This provider manages daemons running supervised by D.J.Bernstein daemontools.
- It tries to detect the service directory, with by order of preference:
+ This provider manages daemons supervised by D.J. Bernstein daemontools.
+ When detecting the service directory it will check, in order of preference:
- * /service
- * /etc/service
- * /var/lib/svscan
+ * `/service`
+ * `/etc/service`
+ * `/var/lib/svscan`
- The daemon directory should be placed in a directory that can be
- by default in:
+ The daemon directory should be in one of the following locations:
- * /var/lib/service
- * /etc
+ * `/var/lib/service`
+ * `/etc`
- or this can be overriden in the service resource parameters::
+ ...or this can be overriden in the resource's attributes:
- service { \"myservice\":
- provider => \"daemontools\",
- path => \"/path/to/daemons\",
- }
+ service { "myservice":
+ provider => "daemontools",
+ path => "/path/to/daemons",
+ }
- This provider supports out of the box:
+ This provider supports out of the box:
- * start/stop (mapped to enable/disable)
- * enable/disable
- * restart
- * status
+ * start/stop (mapped to enable/disable)
+ * enable/disable
+ * restart
+ * status
- If a service has `ensure => \"running\"`, it will link /path/to/daemon to
- /path/to/service, which will automatically enable the service.
+ If a service has `ensure => "running"`, it will link /path/to/daemon to
+ /path/to/service, which will automatically enable the service.
- If a service has `ensure => \"stopped\"`, it will only down the service, not
- remove the /path/to/service link.
+ If a service has `ensure => "stopped"`, it will only shut down the service, not
+ remove the `/path/to/service` link.
- "
+ EOT
commands :svc => "/usr/bin/svc", :svstat => "/usr/bin/svstat"
class << self
attr_writer :defpath
# Determine the daemon path.
def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
unless @defpath
["/var/lib/service", "/etc"].each do |path|
if FileTest.exist?(path)
@defpath = path
break
end
end
raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
end
@defpath
end
end
attr_writer :servicedir
# returns all providers for all existing services in @defpath
# ie enabled or not
def self.instances
path = self.defpath
unless FileTest.directory?(path)
Puppet.notice "Service path #{path} does not exist"
return
end
# reject entries that aren't either a directory
# or don't contain a run file
Dir.entries(path).reject { |e|
fullpath = File.join(path, e)
e =~ /^\./ or ! FileTest.directory?(fullpath) or ! FileTest.exist?(File.join(fullpath,"run"))
}.collect do |name|
new(:name => name, :path => path)
end
end
# returns the daemon dir on this node
def self.daemondir
self.defpath
end
# find the service dir on this node
def servicedir
unless @servicedir
["/service", "/etc/service","/var/lib/svscan"].each do |path|
if FileTest.exist?(path)
@servicedir = path
break
end
end
raise "Could not find service directory" unless @servicedir
end
@servicedir
end
# returns the full path of this service when enabled
# (ie in the service directory)
def service
File.join(self.servicedir, resource[:name])
end
# returns the full path to the current daemon directory
# note that this path can be overriden in the resource
# definition
def daemon
File.join(resource[:path], resource[:name])
end
def status
begin
output = svstat self.service
if output =~ /:\s+up \(/
return :running
end
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
end
:stopped
end
def setupservice
if resource[:manifest]
Puppet.notice "Configuring #{resource[:name]}"
command = [ resource[:manifest], resource[:name] ]
#texecute("setupservice", command)
rv = system("#{command}")
end
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" )
end
def enabled?
case self.status
when :running
# obviously if the daemon is running then it is enabled
return :true
else
# the service is enabled if it is linked
return FileTest.symlink?(self.service) ? :true : :false
end
end
def enable
if ! FileTest.directory?(self.daemon)
Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
self.setupservice
end
if self.daemon
if ! FileTest.symlink?(self.service)
Puppet.notice "Enabling #{self.service}: linking #{self.daemon} -> #{self.service}"
File.symlink(self.daemon, self.service)
end
end
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new( "No daemon directory found for #{self.service}")
end
def disable
begin
if ! FileTest.directory?(self.daemon)
Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
self.setupservice
end
if self.daemon
if FileTest.symlink?(self.service)
Puppet.notice "Disabling #{self.service}: removing link #{self.daemon} -> #{self.service}"
File.unlink(self.service)
end
end
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new( "No daemon directory found for #{self.service}")
end
self.stop
end
def restart
svc "-t", self.service
end
def start
enable unless enabled? == :true
svc "-u", self.service
end
def stop
svc "-d", self.service
end
end
diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb
index 58b808a8e..6030da1e9 100755
--- a/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -1,52 +1,54 @@
# Manage debian services. Start/stop is the same as InitSvc, but enable/disable
# is special.
Puppet::Type.type(:service).provide :debian, :parent => :init do
- desc "Debian's form of `init`-style management.
+ desc <<-EOT
+ Debian's form of `init`-style management.
- The only difference is that this supports service enabling and disabling
- via `update-rc.d` and determines enabled status via `invoke-rc.d`.
+ The only differences from `init` are support for enabling and disabling
+ services via `update-rc.d` and the ability to determine enabled status via
+ `invoke-rc.d`.
- "
+ EOT
commands :update_rc => "/usr/sbin/update-rc.d"
# note this isn't being used as a command until
# http://projects.reductivelabs.com/issues/2538
# is resolved.
commands :invoke_rc => "/usr/sbin/invoke-rc.d"
defaultfor :operatingsystem => [:debian, :ubuntu]
def self.defpath
superclass.defpath
end
# Remove the symlinks
def disable
if `dpkg --compare-versions $(dpkg-query -W --showformat '${Version}' sysv-rc) ge 2.88 ; echo $?`.to_i == 0
update_rc @resource[:name], "disable"
else
update_rc "-f", @resource[:name], "remove"
update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
end
end
def enabled?
# TODO: Replace system call when Puppet::Util.execute gives us a way
# to determine exit status. http://projects.reductivelabs.com/issues/2538
system("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start")
# 104 is the exit status when you query start an enabled service.
# 106 is the exit status when the policy layer supplies a fallback action
# See x-man-page://invoke-rc.d
if [104, 106].include?($CHILD_STATUS.exitstatus)
return :true
else
return :false
end
end
def enable
update_rc "-f", @resource[:name], "remove"
update_rc @resource[:name], "defaults"
end
end
diff --git a/lib/puppet/provider/service/freebsd.rb b/lib/puppet/provider/service/freebsd.rb
index f8c7134f0..5e1a36d46 100644
--- a/lib/puppet/provider/service/freebsd.rb
+++ b/lib/puppet/provider/service/freebsd.rb
@@ -1,139 +1,139 @@
Puppet::Type.type(:service).provide :freebsd, :parent => :init do
- desc "Provider for FreeBSD. Makes use of rcvar argument of init scripts and parses/edits rc files."
+ desc "Provider for FreeBSD. Uses the `rcvar` argument of init scripts and parses/edits rc files."
confine :operatingsystem => [:freebsd]
defaultfor :operatingsystem => [:freebsd]
@@rcconf = '/etc/rc.conf'
@@rcconf_local = '/etc/rc.conf.local'
@@rcconf_dir = '/etc/rc.conf.d'
def self.defpath
superclass.defpath
end
# Executing an init script with the 'rcvar' argument returns
# the service name, rcvar name and whether it's enabled/disabled
def rcvar
rcvar = execute([self.initscript, :rcvar], :failonfail => true, :squelch => false)
rcvar = rcvar.split("\n")
rcvar.delete_if {|str| str =~ /^#\s*$/}
rcvar[1] = rcvar[1].gsub(/^\$/, '')
rcvar
end
# Extract service name
def service_name
name = self.rcvar[0]
self.error("No service name found in rcvar") if name.nil?
name = name.gsub!(/# (.*)/, '\1')
self.error("Service name is empty") if name.nil?
self.debug("Service name is #{name}")
name
end
# Extract rcvar name
def rcvar_name
name = self.rcvar[1]
self.error("No rcvar name found in rcvar") if name.nil?
name = name.gsub!(/(.*)_enable=(.*)/, '\1')
self.error("rcvar name is empty") if name.nil?
self.debug("rcvar name is #{name}")
name
end
# Extract rcvar value
def rcvar_value
value = self.rcvar[1]
self.error("No rcvar value found in rcvar") if value.nil?
value = value.gsub!(/(.*)_enable="?(\w+)"?/, '\2')
self.error("rcvar value is empty") if value.nil?
self.debug("rcvar value is #{value}")
value
end
# Edit rc files and set the service to yes/no
def rc_edit(yesno)
service = self.service_name
rcvar = self.rcvar_name
self.debug("Editing rc files: setting #{rcvar} to #{yesno} for #{service}")
self.rc_add(service, rcvar, yesno) if not self.rc_replace(service, rcvar, yesno)
end
# Try to find an existing setting in the rc files
# and replace the value
def rc_replace(service, rcvar, yesno)
success = false
# Replace in all files, not just in the first found with a match
[@@rcconf, @@rcconf_local, @@rcconf_dir + "/#{service}"].each do |filename|
if File.exists?(filename)
s = File.read(filename)
if s.gsub!(/(#{rcvar}_enable)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"")
File.open(filename, File::WRONLY) { |f| f << s }
self.debug("Replaced in #{filename}")
success = true
end
end
end
success
end
# Add a new setting to the rc files
def rc_add(service, rcvar, yesno)
append = "\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\"\n"
# First, try the one-file-per-service style
if File.exists?(@@rcconf_dir)
File.open(@@rcconf_dir + "/#{service}", File::WRONLY | File::APPEND | File::CREAT, 0644) {
|f| f << append
self.debug("Appended to #{f.path}")
}
else
# Else, check the local rc file first, but don't create it
if File.exists?(@@rcconf_local)
File.open(@@rcconf_local, File::WRONLY | File::APPEND) {
|f| f << append
self.debug("Appended to #{f.path}")
}
else
# At last use the standard rc.conf file
File.open(@@rcconf, File::WRONLY | File::APPEND | File::CREAT, 0644) {
|f| f << append
self.debug("Appended to #{f.path}")
}
end
end
end
def enabled?
if /YES$/ =~ self.rcvar_value
self.debug("Is enabled")
return :true
end
self.debug("Is disabled")
:false
end
def enable
self.debug("Enabling")
self.rc_edit("YES")
end
def disable
self.debug("Disabling")
self.rc_edit("NO")
end
def startcmd
[self.initscript, :onestart]
end
def stopcmd
[self.initscript, :onestop]
end
def statuscmd
[self.initscript, :onestatus]
end
end
diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb
index 20f5d77e6..8928d4459 100644
--- a/lib/puppet/provider/service/gentoo.rb
+++ b/lib/puppet/provider/service/gentoo.rb
@@ -1,50 +1,51 @@
# Manage gentoo services. Start/stop is the same as InitSvc, but enable/disable
# is special.
Puppet::Type.type(:service).provide :gentoo, :parent => :init do
- desc "Gentoo's form of `init`-style service management.
+ desc <<-EOT
+ Gentoo's form of `init`-style service management.
- Uses `rc-update` for service enabling and disabling.
+ Uses `rc-update` for service enabling and disabling.
- "
+ EOT
commands :update => "/sbin/rc-update"
confine :operatingsystem => :gentoo
defaultfor :operatingsystem => :gentoo
def self.defpath
superclass.defpath
end
def disable
output = update :del, @resource[:name], :default
rescue Puppet::ExecutionFailure
raise Puppet::Error, "Could not disable #{self.name}: #{output}"
end
def enabled?
begin
output = update :show
rescue Puppet::ExecutionFailure
return :false
end
line = output.split(/\n/).find { |l| l.include?(@resource[:name]) }
return :false unless line
# If it's enabled then it will print output showing service | runlevel
if output =~ /^\s*#{@resource[:name]}\s*\|\s*(boot|default)/
return :true
else
return :false
end
end
def enable
output = update :add, @resource[:name], :default
rescue Puppet::ExecutionFailure
raise Puppet::Error, "Could not enable #{self.name}: #{output}"
end
end
diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb
index 447c01aa5..f13e9c8e1 100755
--- a/lib/puppet/provider/service/init.rb
+++ b/lib/puppet/provider/service/init.rb
@@ -1,141 +1,134 @@
# The standard init-based service type. Many other service types are
# customizations of this module.
Puppet::Type.type(:service).provide :init, :parent => :base do
- desc "Standard init service management.
-
- This provider assumes that the init script has no `status` command,
- because so few scripts do, so you need to either provide a status
- command or specify via `hasstatus` that one already exists in the
- init script.
-
-"
+ desc "Standard `init`-style service management."
class << self
attr_accessor :defpath
end
case Facter["operatingsystem"].value
when "FreeBSD"
@defpath = ["/etc/rc.d", "/usr/local/etc/rc.d"]
when "HP-UX"
@defpath = "/sbin/init.d"
else
@defpath = "/etc/init.d"
end
# We can't confine this here, because the init path can be overridden.
#confine :exists => @defpath
# List all services of this type.
def self.instances
get_services(self.defpath)
end
def self.get_services(defpath, exclude=[])
defpath = [defpath] unless defpath.is_a? Array
instances = []
defpath.each do |path|
unless FileTest.directory?(path)
Puppet.debug "Service path #{path} does not exist"
next
end
check = [:ensure]
check << :enable if public_method_defined? :enabled?
Dir.entries(path).each do |name|
fullpath = File.join(path, name)
next if name =~ /^\./
next if exclude.include? name
next if not FileTest.executable?(fullpath)
instances << new(:name => name, :path => path, :hasstatus => true)
end
end
instances
end
# Mark that our init script supports 'status' commands.
def hasstatus=(value)
case value
when true, "true"; @parameters[:hasstatus] = true
when false, "false"; @parameters[:hasstatus] = false
else
raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}"
end
end
# Where is our init script?
def initscript
@initscript ||= self.search(@resource[:name])
end
def paths
@paths ||= @resource[:path].find_all do |path|
if File.directory?(path)
true
else
if File.exist?(path) and ! File.directory?(path)
self.debug "Search path #{path} is not a directory"
else
self.debug "Search path #{path} does not exist"
end
false
end
end
end
def search(name)
paths.each { |path|
fqname = File.join(path,name)
begin
stat = File.stat(fqname)
rescue
# should probably rescue specific errors...
self.debug("Could not find #{name} in #{path}")
next
end
# if we've gotten this far, we found a valid script
return fqname
}
paths.each { |path|
fqname_sh = File.join(path,"#{name}.sh")
begin
stat = File.stat(fqname_sh)
rescue
# should probably rescue specific errors...
self.debug("Could not find #{name}.sh in #{path}")
next
end
# if we've gotten this far, we found a valid script
return fqname_sh
}
raise Puppet::Error, "Could not find init script for '#{name}'"
end
# The start command is just the init scriptwith 'start'.
def startcmd
[initscript, :start]
end
# The stop command is just the init script with 'stop'.
def stopcmd
[initscript, :stop]
end
def restartcmd
(@resource[:hasrestart] == :true) && [initscript, :restart]
end
# If it was specified that the init script has a 'status' command, then
# we just return that; otherwise, we return false, which causes it to
# fallback to other mechanisms.
def statuscmd
(@resource[:hasstatus] == :true) && [initscript, :status]
end
end
diff --git a/lib/puppet/provider/service/launchd.rb b/lib/puppet/provider/service/launchd.rb
index 9d813bd5a..73d4b3c07 100644
--- a/lib/puppet/provider/service/launchd.rb
+++ b/lib/puppet/provider/service/launchd.rb
@@ -1,266 +1,299 @@
require 'facter/util/plist'
-
Puppet::Type.type(:service).provide :launchd, :parent => :base do
- desc "launchd service management framework.
+ desc <<-EOT
+ This provider manages jobs with `launchd`, which is the default service
+ framework for Mac OS X (and may be available for use on other platforms).
- This provider manages jobs with launchd, which is the default service framework for
- Mac OS X and is potentially available for use on other platforms.
+ For `launchd` documentation, see:
- See:
-
- * http://developer.apple.com/macosx/launchd.html
- * http://launchd.macosforge.org/
+ * <http://developer.apple.com/macosx/launchd.html>
+ * <http://launchd.macosforge.org/>
- This provider reads plists out of the following directories:
-
- * /System/Library/LaunchDaemons
- * /System/Library/LaunchAgents
- * /Library/LaunchDaemons
- * /Library/LaunchAgents
+ This provider reads plists out of the following directories:
- ...and builds up a list of services based upon each plist's \"Label\" entry.
+ * `/System/Library/LaunchDaemons`
+ * `/System/Library/LaunchAgents`
+ * `/Library/LaunchDaemons`
+ * `/Library/LaunchAgents`
- This provider supports:
-
- * ensure => running/stopped,
- * enable => true/false
- * status
- * restart
+ ...and builds up a list of services based upon each plist's "Label" entry.
- Here is how the Puppet states correspond to launchd states:
-
- * stopped --- job unloaded
- * started --- job loaded
- * enabled --- 'Disable' removed from job plist file
- * disabled --- 'Disable' added to job plist file
+ This provider supports:
+
+ * ensure => running/stopped,
+ * enable => true/false
+ * status
+ * restart
+
+ Here is how the Puppet states correspond to `launchd` states:
+
+ * stopped --- job unloaded
+ * started --- job loaded
+ * enabled --- 'Disable' removed from job plist file
+ * disabled --- 'Disable' added to job plist file
- Note that this allows you to do something launchctl can't do, which is to
- be in a state of \"stopped/enabled\ or \"running/disabled\".
+ Note that this allows you to do something `launchctl` can't do, which is to
+ be in a state of "stopped/enabled" or "running/disabled".
- "
+ EOT
+
+ include Puppet::Util::Warnings
commands :launchctl => "/bin/launchctl"
- commands :sw_vers => "/usr/bin/sw_vers"
- commands :plutil => "/usr/bin/plutil"
+ commands :sw_vers => "/usr/bin/sw_vers"
+ commands :plutil => "/usr/bin/plutil"
defaultfor :operatingsystem => :darwin
- confine :operatingsystem => :darwin
+ confine :operatingsystem => :darwin
has_feature :enableable
+ mk_resource_methods
- Launchd_Paths = ["/Library/LaunchAgents",
- "/Library/LaunchDaemons",
- "/System/Library/LaunchAgents",
- "/System/Library/LaunchDaemons",]
+ Launchd_Paths = [ "/Library/LaunchAgents",
+ "/Library/LaunchDaemons",
+ "/System/Library/LaunchAgents",
+ "/System/Library/LaunchDaemons"]
Launchd_Overrides = "/var/db/launchd.db/com.apple.launchd/overrides.plist"
+
+ # Caching is enabled through the following three methods. Self.prefetch will
+ # call self.instances to create an instance for each service. Self.flush will
+ # clear out our cache when we're done.
+ def self.prefetch(resources)
+ instances.each do |prov|
+ if resource = resources[prov.name]
+ resource.provider = prov
+ end
+ end
+ end
-
- # Read a plist, whether its format is XML or in Apple's "binary1"
- # format.
- def self.read_plist(path)
- Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', path))
+ # Self.instances will return an array with each element being a hash
+ # containing the name, provider, path, and status of each service on the
+ # system.
+ def self.instances
+ jobs = self.jobsearch
+ @job_list ||= self.job_list
+ jobs.keys.collect do |job|
+ job_status = @job_list.has_key?(job) ? :running : :stopped
+ new(:name => job, :provider => :launchd, :path => jobs[job], :status => job_status)
+ end
end
- # returns a label => path map for either all jobs, or just a single
- # job if the label is specified
+ # Sets a class instance variable with a hash of all launchd plist files that
+ # are found on the system. The key of the hash is the job id and the value
+ # is the path to the file. If a label is passed, we return the job id and
+ # path for that specific job.
def self.jobsearch(label=nil)
- label_to_path_map = {}
- Launchd_Paths.each do |path|
- if FileTest.exists?(path)
- Dir.entries(path).each do |f|
- next if f =~ /^\..*$/
- next if FileTest.directory?(f)
- fullpath = File.join(path, f)
- if FileTest.file?(fullpath) and job = read_plist(fullpath) and job.has_key?("Label")
- if job["Label"] == label
- return { label => fullpath }
- else
- label_to_path_map[job["Label"]] = fullpath
- end
+ @label_to_path_map ||= {}
+ if @label_to_path_map.empty?
+ Launchd_Paths.each do |path|
+ Dir.glob(File.join(path,'*')).each do |filepath|
+ next if ! File.file?(filepath)
+ job = read_plist(filepath)
+ if job.has_key?("Label") and job["Label"] == label
+ return { label => filepath }
+ else
+ @label_to_path_map[job["Label"]] = filepath
end
end
end
end
- # if we didn't find the job above and we should have, error.
- raise Puppet::Error.new("Unable to find launchd plist for job: #{label}") if label
- # if returning all jobs
- label_to_path_map
+ if label
+ if @label_to_path_map.has_key? label
+ return { label => @label_to_path_map[label] }
+ else
+ raise Puppet::Error.new("Unable to find launchd plist for job: #{label}")
+ end
+ else
+ @label_to_path_map
+ end
end
-
- def self.instances
- jobs = self.jobsearch
- jobs.keys.collect do |job|
- new(:name => job, :provider => :launchd, :path => jobs[job])
+ # This status method lists out all currently running services.
+ # This hash is returned at the end of the method.
+ def self.job_list
+ @job_list = Hash.new
+ begin
+ output = launchctl :list
+ raise Puppet::Error.new("launchctl list failed to return any data.") if output.nil?
+ output.split("\n").each do |line|
+ @job_list[line.split(/\s/).last] = :running
+ end
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new("Unable to determine status of #{resource[:name]}")
end
+ @job_list
+ end
+
+ # Launchd implemented plist overrides in version 10.6.
+ # This method checks the major_version of OS X and returns true if
+ # it is 10.6 or greater. This allows us to implement different plist
+ # behavior for versions >= 10.6
+ def has_macosx_plist_overrides?
+ @product_version ||= self.class.get_macosx_version_major
+ return true unless /^10\.[0-5]/.match(@product_version)
+ return false
end
+ # Read a plist, whether its format is XML or in Apple's "binary1"
+ # format.
+ def self.read_plist(path)
+ Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', path))
+ end
+
+ # Clean out the @property_hash variable containing the cached list of services
+ def flush
+ @property_hash.clear
+ end
+
+ def exists?
+ Puppet.debug("Puppet::Provider::Launchd:Ensure for #{@property_hash[:name]}: #{@property_hash[:ensure]}")
+ @property_hash[:ensure] != :absent
+ end
def self.get_macosx_version_major
- return @macosx_version_major if defined?(@macosx_version_major)
+ return @macosx_version_major if @macosx_version_major
begin
# Make sure we've loaded all of the facts
Facter.loadfacts
-
if Facter.value(:macosx_productversion_major)
product_version_major = Facter.value(:macosx_productversion_major)
else
# TODO: remove this code chunk once we require Facter 1.5.5 or higher.
- Puppet.warning("DEPRECATION WARNING: Future versions of the launchd provider will require Facter 1.5.5 or newer.")
+ warnonce("DEPRECATION WARNING: Future versions of the launchd provider will require Facter 1.5.5 or newer.")
product_version = Facter.value(:macosx_productversion)
fail("Could not determine OS X version from Facter") if product_version.nil?
product_version_major = product_version.scan(/(\d+)\.(\d+)./).join(".")
end
fail("#{product_version_major} is not supported by the launchd provider") if %w{10.0 10.1 10.2 10.3}.include?(product_version_major)
@macosx_version_major = product_version_major
return @macosx_version_major
rescue Puppet::ExecutionFailure => detail
fail("Could not determine OS X version: #{detail}")
end
end
# finds the path for a given label and returns the path and parsed plist
# as an array of [path, plist]. Note plist is really a Hash here.
def plist_from_label(label)
job = self.class.jobsearch(label)
job_path = job[label]
if FileTest.file?(job_path)
job_plist = self.class.read_plist(job_path)
else
raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}")
end
[job_path, job_plist]
end
-
- def status
- # launchctl list <jobname> exits zero if the job is loaded
- # and non-zero if it isn't. Simple way to check... but is only
- # available on OS X 10.5 unfortunately, so we grab the whole list
- # and check if our resource is included. The output formats differ
- # between 10.4 and 10.5, thus the necessity for splitting
- begin
- output = launchctl :list
- raise Puppet::Error.new("launchctl list failed to return any data.") if output.nil?
- output.split("\n").each do |j|
- return :running if j.split(/\s/).last == resource[:name]
- end
- return :stopped
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new("Unable to determine status of #{resource[:name]}")
- end
- end
-
-
# start the service. To get to a state of running/enabled, we need to
# conditionally enable at load, then disable by modifying the plist file
# directly.
def start
job_path, job_plist = plist_from_label(resource[:name])
did_enable_job = false
cmds = []
cmds << :launchctl << :load
if self.enabled? == :false # launchctl won't load disabled jobs
cmds << "-w"
did_enable_job = true
end
cmds << job_path
begin
execute(cmds)
rescue Puppet::ExecutionFailure
raise Puppet::Error.new("Unable to start service: #{resource[:name]} at path: #{job_path}")
end
# As load -w clears the Disabled flag, we need to add it in after
self.disable if did_enable_job and resource[:enable] == :false
end
def stop
job_path, job_plist = plist_from_label(resource[:name])
did_disable_job = false
cmds = []
cmds << :launchctl << :unload
if self.enabled? == :true # keepalive jobs can't be stopped without disabling
cmds << "-w"
did_disable_job = true
end
cmds << job_path
begin
execute(cmds)
rescue Puppet::ExecutionFailure
raise Puppet::Error.new("Unable to stop service: #{resource[:name]} at path: #{job_path}")
end
# As unload -w sets the Disabled flag, we need to add it in after
self.enable if did_disable_job and resource[:enable] == :true
end
# launchd jobs are enabled by default. They are only disabled if the key
# "Disabled" is set to true, but it can also be set to false to enable it.
- # In 10.6, the Disabled key in the job plist is consulted, but only if there
- # is no entry in the global overrides plist.
+ # Starting in 10.6, the Disabled key in the job plist is consulted, but only
+ # if there is no entry in the global overrides plist.
# We need to draw a distinction between undefined, true and false for both
# locations where the Disabled flag can be defined.
def enabled?
job_plist_disabled = nil
overrides_disabled = nil
job_path, job_plist = plist_from_label(resource[:name])
job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled")
- if self.class.get_macosx_version_major == "10.6"
+ if has_macosx_plist_overrides?
if FileTest.file?(Launchd_Overrides) and overrides = self.class.read_plist(Launchd_Overrides)
if overrides.has_key?(resource[:name])
overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")
end
end
end
if overrides_disabled.nil?
if job_plist_disabled.nil? or job_plist_disabled == false
return :true
end
elsif overrides_disabled == false
return :true
end
:false
end
# enable and disable are a bit hacky. We write out the plist with the appropriate value
# rather than dealing with launchctl as it is unable to change the Disabled flag
# without actually loading/unloading the job.
- # In 10.6 we need to write out a disabled key to the global overrides plist, in earlier
- # versions this is stored in the job plist itself.
+ # Starting in 10.6 we need to write out a disabled key to the global
+ # overrides plist, in earlier versions this is stored in the job plist itself.
def enable
- if self.class.get_macosx_version_major == "10.6"
+ if has_macosx_plist_overrides?
overrides = self.class.read_plist(Launchd_Overrides)
overrides[resource[:name]] = { "Disabled" => false }
Plist::Emit.save_plist(overrides, Launchd_Overrides)
else
job_path, job_plist = plist_from_label(resource[:name])
if self.enabled? == :false
job_plist.delete("Disabled")
Plist::Emit.save_plist(job_plist, job_path)
end
end
end
def disable
- if self.class.get_macosx_version_major == "10.6"
+ if has_macosx_plist_overrides?
overrides = self.class.read_plist(Launchd_Overrides)
overrides[resource[:name]] = { "Disabled" => true }
Plist::Emit.save_plist(overrides, Launchd_Overrides)
else
job_path, job_plist = plist_from_label(resource[:name])
job_plist["Disabled"] = true
Plist::Emit.save_plist(job_plist, job_path)
end
end
end
diff --git a/lib/puppet/provider/service/redhat.rb b/lib/puppet/provider/service/redhat.rb
index e851a488d..b600e1b2e 100755
--- a/lib/puppet/provider/service/redhat.rb
+++ b/lib/puppet/provider/service/redhat.rb
@@ -1,76 +1,75 @@
# Manage Red Hat services. Start/stop uses /sbin/service and enable/disable uses chkconfig
Puppet::Type.type(:service).provide :redhat, :parent => :init, :source => :init do
- desc "Red Hat's (and probably many others) form of `init`-style service management:
-
- Uses `chkconfig` for service enabling and disabling.
+ desc "Red Hat's (and probably many others') form of `init`-style service
+ management. Uses `chkconfig` for service enabling and disabling.
"
commands :chkconfig => "/sbin/chkconfig", :service => "/sbin/service"
defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles, :oel, :ovm]
def self.instances
# this exclude list is all from /sbin/service (5.x), but I did not exclude kudzu
self.get_services(['/etc/init.d'], ['functions', 'halt', 'killall', 'single', 'linuxconf'])
end
def self.defpath
superclass.defpath
end
# Remove the symlinks
def disable
output = chkconfig(@resource[:name], :off)
rescue Puppet::ExecutionFailure
raise Puppet::Error, "Could not disable #{self.name}: #{output}"
end
def enabled?
begin
output = chkconfig(@resource[:name])
rescue Puppet::ExecutionFailure
return :false
end
# If it's disabled on SuSE, then it will print output showing "off"
# at the end
if output =~ /.* off$/
return :false
end
:true
end
# Don't support them specifying runlevels; always use the runlevels
# in the init scripts.
def enable
output = chkconfig(@resource[:name], :on)
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, "Could not enable #{self.name}: #{detail}"
end
def initscript
raise Puppet::Error, "Do not directly call the init script for '#{@resource[:name]}'; use 'service' instead"
end
# use hasstatus=>true when its set for the provider.
def statuscmd
((@resource.provider.get(:hasstatus) == true) || (@resource[:hasstatus] == :true)) && [command(:service), @resource[:name], "status"]
end
def restartcmd
(@resource[:hasrestart] == :true) && [command(:service), @resource[:name], "restart"]
end
def startcmd
[command(:service), @resource[:name], "start"]
end
def stopcmd
[command(:service), @resource[:name], "stop"]
end
end
diff --git a/lib/puppet/provider/service/runit.rb b/lib/puppet/provider/service/runit.rb
index 736e3db71..c923bd28e 100644
--- a/lib/puppet/provider/service/runit.rb
+++ b/lib/puppet/provider/service/runit.rb
@@ -1,103 +1,103 @@
# Daemontools service management
#
# author Brice Figureau <brice-puppet@daysofwonder.com>
Puppet::Type.type(:service).provide :runit, :parent => :daemontools do
- desc "Runit service management.
+ desc <<-EOT
+ Runit service management.
- This provider manages daemons running supervised by Runit.
- It tries to detect the service directory, with by order of preference:
+ This provider manages daemons running supervised by Runit.
+ When detecting the service directory it will check, in order of preference:
- * /service
- * /var/service
- * /etc/service
+ * `/service`
+ * `/var/service`
+ * `/etc/service`
- The daemon directory should be placed in a directory that can be
- by default in:
+ The daemon directory should be in one of the following locations:
- * /etc/sv
+ * `/etc/sv`
- or this can be overriden in the service resource parameters::
+ or this can be overriden in the service resource parameters::
- service { \"myservice\":
- provider => \"runit\",
- path => \"/path/to/daemons\",
- }
+ service { "myservice":
+ provider => "runit",
+ path => "/path/to/daemons",
+ }
- This provider supports out of the box:
+ This provider supports out of the box:
- * start/stop
- * enable/disable
- * restart
- * status
+ * start/stop
+ * enable/disable
+ * restart
+ * status
-"
+ EOT
commands :sv => "/usr/bin/sv"
class << self
# this is necessary to autodetect a valid resource
# default path, since there is no standard for such directory.
def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
unless @defpath
["/etc/sv", "/var/lib/service"].each do |path|
if FileTest.exist?(path)
@defpath = path
break
end
end
raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
end
@defpath
end
end
# find the service dir on this node
def servicedir
unless @servicedir
["/service", "/etc/service","/var/service"].each do |path|
if FileTest.exist?(path)
@servicedir = path
break
end
end
raise "Could not find service directory" unless @servicedir
end
@servicedir
end
def status
begin
output = sv "status", self.daemon
return :running if output =~ /^run: /
rescue Puppet::ExecutionFailure => detail
unless detail.message =~ /(warning: |runsv not running$)/
raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
end
end
:stopped
end
def stop
sv "stop", self.service
end
def start
enable unless enabled? == :true
sv "start", self.service
end
def restart
sv "restart", self.service
end
# disable by removing the symlink so that runit
# doesn't restart our service behind our back
# note that runit doesn't need to perform a stop
# before a disable
def disable
# unlink the daemon symlink to disable it
File.unlink(self.service) if FileTest.symlink?(self.service)
end
end
diff --git a/lib/puppet/provider/service/smf.rb b/lib/puppet/provider/service/smf.rb
index f6f221a7c..c8cc262e9 100755
--- a/lib/puppet/provider/service/smf.rb
+++ b/lib/puppet/provider/service/smf.rb
@@ -1,103 +1,104 @@
# Solaris 10 SMF-style services.
Puppet::Type.type(:service).provide :smf, :parent => :base do
- desc "Support for Sun's new Service Management Framework.
+ desc <<-EOT
+ Support for Sun's new Service Management Framework.
- Starting a service is effectively equivalent to enabling it, so there is
- only support for starting and stopping services, which also enables and
- disables them, respectively.
+ Starting a service is effectively equivalent to enabling it, so there is
+ only support for starting and stopping services, which also enables and
+ disables them, respectively.
- By specifying manifest => \"/path/to/service.xml\", the SMF manifest will
- be imported if it does not exist.
+ By specifying `manifest => "/path/to/service.xml"`, the SMF manifest will
+ be imported if it does not exist.
- "
+ EOT
defaultfor :operatingsystem => :solaris
confine :operatingsystem => :solaris
commands :adm => "/usr/sbin/svcadm", :svcs => "/usr/bin/svcs"
commands :svccfg => "/usr/sbin/svccfg"
def setupservice
if resource[:manifest]
[command(:svcs), "-l", @resource[:name]]
if $CHILD_STATUS.exitstatus == 1
Puppet.notice "Importing #{@resource[:manifest]} for #{@resource[:name]}"
svccfg :import, resource[:manifest]
end
end
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new( "Cannot config #{self.name} to enable it: #{detail}" )
end
def enable
self.start
end
def enabled?
case self.status
when :running
return :true
else
return :false
end
end
def disable
self.stop
end
def restartcmd
[command(:adm), :restart, @resource[:name]]
end
def startcmd
self.setupservice
case self.status
when :maintenance
[command(:adm), :clear, @resource[:name]]
else
[command(:adm), :enable, @resource[:name]]
end
end
def status
if @resource[:status]
super
return
end
begin
# get the current state and the next state, and if the next
# state is set (i.e. not "-") use it for state comparison
states = svcs("-H", "-o", "state,nstate", @resource[:name]).chomp.split
state = states[1] == "-" ? states[0] : states[1]
rescue Puppet::ExecutionFailure
info "Could not get status on service #{self.name}"
return :stopped
end
case state
when "online"
#self.warning "matched running #{line.inspect}"
return :running
when "offline", "disabled", "uninitialized"
#self.warning "matched stopped #{line.inspect}"
return :stopped
when "maintenance"
return :maintenance
when "legacy_run"
raise Puppet::Error,
"Cannot manage legacy services through SMF"
else
raise Puppet::Error,
"Unmanageable state '#{state}' on service #{self.name}"
end
end
def stopcmd
[command(:adm), :disable, @resource[:name]]
end
end
diff --git a/lib/puppet/provider/service/src.rb b/lib/puppet/provider/service/src.rb
index 2bd643c0b..eced271d4 100755
--- a/lib/puppet/provider/service/src.rb
+++ b/lib/puppet/provider/service/src.rb
@@ -1,87 +1,86 @@
# AIX System Resource controller (SRC)
Puppet::Type.type(:service).provide :src, :parent => :base do
desc "Support for AIX's System Resource controller.
- Services are started/stopped based on the stopsrc and startsrc
- commands, and some services can be refreshed with refresh command.
+ Services are started/stopped based on the `stopsrc` and `startsrc`
+ commands, and some services can be refreshed with `refresh` command.
- * Enabling and disableing services is not supported, as it requires
- modifications to /etc/inittab.
-
- * Starting and stopping groups of subsystems is not yet supported
+ Enabling and disabling services is not supported, as it requires
+ modifications to `/etc/inittab`. Starting and stopping groups of subsystems
+ is not yet supported.
"
defaultfor :operatingsystem => :aix
confine :operatingsystem => :aix
commands :stopsrc => "/usr/bin/stopsrc"
commands :startsrc => "/usr/bin/startsrc"
commands :refresh => "/usr/bin/refresh"
commands :lssrc => "/usr/bin/lssrc"
has_feature :refreshable
def startcmd
[command(:startsrc), "-s", @resource[:name]]
end
def stopcmd
[command(:stopsrc), "-s", @resource[:name]]
end
def restart
execute([command(:lssrc), "-Ss", @resource[:name]]).each do |line|
args = line.split(":")
next unless args[0] == @resource[:name]
# Subsystems with the -K flag can get refreshed (HUPed)
# While subsystems with -S (signals) must be stopped/started
method = args[11]
do_refresh = case method
when "-K" then :true
when "-S" then :false
else self.fail("Unknown service communication method #{method}")
end
begin
if do_refresh == :true
execute([command(:refresh), "-s", @resource[:name]])
else
self.stop
self.start
end
return :true
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new("Unable to restart service #{@resource[:name]}, error was: #{detail}" )
end
end
self.fail("No such service found")
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" )
end
def status
execute([command(:lssrc), "-s", @resource[:name]]).each do |line|
args = line.split
# This is the header line
next unless args[0] == @resource[:name]
# PID is the 3rd field, but inoperative subsystems
# skip this so split doesn't work right
state = case args[-1]
when "active" then :running
when "inoperative" then :stopped
end
Puppet.debug("Service #{@resource[:name]} is #{args[-1]}")
return state
end
self.fail("No such service found")
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" )
end
end
diff --git a/lib/puppet/provider/service/systemd.rb b/lib/puppet/provider/service/systemd.rb
index b6b3b386f..c67a437c5 100755
--- a/lib/puppet/provider/service/systemd.rb
+++ b/lib/puppet/provider/service/systemd.rb
@@ -1,64 +1,64 @@
# Manage systemd services using /bin/systemctl
Puppet::Type.type(:service).provide :systemd, :parent => :base do
- desc "Manage systemd services using /bin/systemctl"
+ desc "Manages `systemd` services using `/bin/systemctl`."
commands :systemctl => "/bin/systemctl"
#defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles, :oel, :ovm]
def self.instances
i = []
output = `systemctl list-units --full --all --no-pager`
output.scan(/^(\S+)\s+(loaded|error)\s+(active|inactive)\s+(active|waiting|running|plugged|mounted|dead|exited|listening|elapsed)\s*?(\S.*?)?$/i).each do |m|
i << m[0]
end
return i
rescue Puppet::ExecutionFailure
return []
end
def disable
output = systemctl(:disable, @resource[:name])
rescue Puppet::ExecutionFailure
raise Puppet::Error, "Could not disable #{self.name}: #{output}"
end
def enabled?
begin
systemctl("is-enabled", @resource[:name])
rescue Puppet::ExecutionFailure
return :false
end
:true
end
def status
begin
output = systemctl("is-active", @resource[:name])
rescue Puppet::ExecutionFailure
return :stopped
end
return :running
end
def enable
output = systemctl("enable", @resource[:name])
rescue Puppet::ExecutionFailure
raise Puppet::Error, "Could not enable #{self.name}: #{output}"
end
def restartcmd
[command(:systemctl), "restart", @resource[:name]]
end
def startcmd
[command(:systemctl), "start", @resource[:name]]
end
def stopcmd
[command(:systemctl), "stop", @resource[:name]]
end
end
diff --git a/lib/puppet/provider/service/upstart.rb b/lib/puppet/provider/service/upstart.rb
index 54971eeac..5249a914c 100755
--- a/lib/puppet/provider/service/upstart.rb
+++ b/lib/puppet/provider/service/upstart.rb
@@ -1,73 +1,71 @@
Puppet::Type.type(:service).provide :upstart, :parent => :init do
- desc "Ubuntu service manager upstart.
+ desc "Ubuntu service management with `upstart`.
- This provider manages upstart jobs which have replaced initd.
-
- See:
- * http://upstart.ubuntu.com/
+ This provider manages `upstart` jobs, which have replaced `initd` services
+ on Ubuntu. For `upstart` documentation, see <http://upstart.ubuntu.com/>.
"
# confine to :ubuntu for now because I haven't tested on other platforms
confine :operatingsystem => :ubuntu #[:ubuntu, :fedora, :debian]
commands :start => "/sbin/start",
:stop => "/sbin/stop",
:restart => "/sbin/restart",
:status_exec => "/sbin/status",
:initctl => "/sbin/initctl"
# upstart developer haven't implemented initctl enable/disable yet:
# http://www.linuxplanet.com/linuxplanet/tutorials/7033/2/
# has_feature :enableable
def self.instances
instances = []
execpipe("#{command(:initctl)} list") { |process|
process.each { |line|
# needs special handling of services such as network-interface:
# initctl list:
# network-interface (lo) start/running
# network-interface (eth0) start/running
# network-interface-security start/running
name = \
if matcher = line.match(/^(network-interface)\s\(([^\)]+)\)/)
"#{matcher[1]} INTERFACE=#{matcher[2]}"
else
line.split.first
end
instances << new(:name => name)
}
}
instances
end
def startcmd
[command(:start), @resource[:name]]
end
def stopcmd
[command(:stop), @resource[:name]]
end
def restartcmd
(@resource[:hasrestart] == :true) && [command(:restart), @resource[:name]]
end
def status
# allows user override of status command
if @resource[:status]
ucommand(:status, false)
if $?.exitstatus == 0
return :running
else
return :stopped
end
else
output = status_exec(@resource[:name].split)
if (! $?.nil?) && (output =~ /start\//)
return :running
else
return :stopped
end
end
end
end
diff --git a/lib/puppet/provider/service/windows.rb b/lib/puppet/provider/service/windows.rb
index 289be697a..e773fa546 100644
--- a/lib/puppet/provider/service/windows.rb
+++ b/lib/puppet/provider/service/windows.rb
@@ -1,110 +1,110 @@
# Windows Service Control Manager (SCM) provider
require 'win32/service' if Puppet.features.microsoft_windows?
Puppet::Type.type(:service).provide :windows do
- desc "Support for Windows Service Control Manager (SCM).
+ desc <<-EOT
+ Support for Windows Service Control Manager (SCM).
- Services are controlled according to win32-service gem.
-
- * All SCM operations (start/stop/enable/disable/query) are supported.
-
- * Control of service groups (dependencies) is not yet supported."
+ Services are controlled according to the capabilities of the `win32-service`
+ gem. All SCM operations (start/stop/enable/disable/query) are supported.
+ Control of service groups (dependencies) is not yet supported.
+ EOT
defaultfor :operatingsystem => :windows
- confine :operatingsystem => :windows
+ confine :operatingsystem => :windows
has_feature :refreshable
def enable
w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_AUTO_START )
raise Puppet::Error.new("Win32 service enable of #{@resource[:name]} failed" ) if( w32ss.nil? )
rescue Win32::Service::Error => detail
raise Puppet::Error.new("Cannot enable #{@resource[:name]}, error was: #{detail}" )
end
def disable
w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_DISABLED )
raise Puppet::Error.new("Win32 service disable of #{@resource[:name]} failed" ) if( w32ss.nil? )
rescue Win32::Service::Error => detail
raise Puppet::Error.new("Cannot disable #{@resource[:name]}, error was: #{detail}" )
end
def manual_start
w32ss = Win32::Service.configure( 'service_name' => @resource[:name], 'start_type' => Win32::Service::SERVICE_DEMAND_START )
raise Puppet::Error.new("Win32 service manual enable of #{@resource[:name]} failed" ) if( w32ss.nil? )
rescue Win32::Service::Error => detail
raise Puppet::Error.new("Cannot enable #{@resource[:name]} for manual start, error was: #{detail}" )
end
def enabled?
w32ss = Win32::Service.config_info( @resource[:name] )
raise Puppet::Error.new("Win32 service query of #{@resource[:name]} failed" ) unless( !w32ss.nil? && w32ss.instance_of?( Struct::ServiceConfigInfo ) )
debug("Service #{@resource[:name]} start type is #{w32ss.start_type}")
case w32ss.start_type
when Win32::Service.get_start_type(Win32::Service::SERVICE_AUTO_START),
Win32::Service.get_start_type(Win32::Service::SERVICE_BOOT_START),
Win32::Service.get_start_type(Win32::Service::SERVICE_SYSTEM_START)
:true
when Win32::Service.get_start_type(Win32::Service::SERVICE_DEMAND_START)
:manual
when Win32::Service.get_start_type(Win32::Service::SERVICE_DISABLED)
:false
else
raise Puppet::Error.new("Unknown start type: #{w32ss.start_type}")
end
rescue Win32::Service::Error => detail
raise Puppet::Error.new("Cannot get start type for #{@resource[:name]}, error was: #{detail}" )
end
def start
if enabled? == :false
# If disabled and not managing enable, respect disabled and fail.
if @resource[:enable].nil?
raise Puppet::Error, "Will not start disabled service #{@resource[:name]} without managing enable. Specify 'enable => false' to override."
# Otherwise start. If enable => false, we will later sync enable and
# disable the service again.
elsif @resource[:enable] == :true
enable
else
manual_start
end
end
Win32::Service.start( @resource[:name] )
rescue Win32::Service::Error => detail
raise Puppet::Error.new("Cannot start #{@resource[:name]}, error was: #{detail}" )
end
def stop
Win32::Service.stop( @resource[:name] )
rescue Win32::Service::Error => detail
raise Puppet::Error.new("Cannot stop #{@resource[:name]}, error was: #{detail}" )
end
def restart
self.stop
self.start
end
def status
w32ss = Win32::Service.status( @resource[:name] )
raise Puppet::Error.new("Win32 service query of #{@resource[:name]} failed" ) unless( !w32ss.nil? && w32ss.instance_of?( Struct::ServiceStatus ) )
state = case w32ss.current_state
when "stopped", "pause pending", "stop pending", "paused" then :stopped
when "running", "continue pending", "start pending" then :running
else
raise Puppet::Error.new("Unknown service state '#{w32ss.current_state}' for service '#{@resource[:name]}'")
end
debug("Service #{@resource[:name]} is #{w32ss.current_state}")
return state
rescue Win32::Service::Error => detail
raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" )
end
# returns all providers for all existing services and startup state
def self.instances
Win32::Service.services.collect { |s| new(:name => s.service_name) }
end
end
diff --git a/lib/puppet/provider/user/aix.rb b/lib/puppet/provider/user/aix.rb
index 032d2b536..a33ed677c 100755
--- a/lib/puppet/provider/user/aix.rb
+++ b/lib/puppet/provider/user/aix.rb
@@ -1,353 +1,353 @@
#
# User Puppet provider for AIX. It uses standard commands to manage users:
# mkuser, rmuser, lsuser, chuser
#
# Notes:
# - AIX users can have expiry date defined with minute granularity,
# but puppet does not allow it. There is a ticket open for that (#5431)
# - AIX maximum password age is in WEEKs, not days
#
# See http://projects.puppetlabs.com/projects/puppet/wiki/Development_Provider_Development
# for more information
#
# Author:: Hector Rivas Gandara <keymon@gmail.com>
#
require 'puppet/provider/aixobject'
require 'tempfile'
require 'date'
Puppet::Type.type(:user).provide :aix, :parent => Puppet::Provider::AixObject do
- desc "User management for AIX! Users are managed with mkuser, rmuser, chuser, lsuser"
+ desc "User management for AIX."
# This will the the default provider for this platform
defaultfor :operatingsystem => :aix
confine :operatingsystem => :aix
# Commands that manage the element
commands :list => "/usr/sbin/lsuser"
commands :add => "/usr/bin/mkuser"
commands :delete => "/usr/sbin/rmuser"
commands :modify => "/usr/bin/chuser"
-
+
commands :lsgroup => "/usr/sbin/lsgroup"
commands :chpasswd => "/bin/chpasswd"
# Provider features
has_features :manages_aix_lam
has_features :manages_homedir, :manages_passwords
has_features :manages_expiry, :manages_password_age
# Attribute verification (TODO)
#verify :gid, "GID must be an string or int of a valid group" do |value|
# value.is_a? String || value.is_a? Integer
#end
#
#verify :groups, "Groups must be comma-separated" do |value|
# value !~ /\s/
#end
# User attributes to ignore from AIX output.
def self.attribute_ignore
[]
end
# AIX attributes to properties mapping.
- #
+ #
# Valid attributes to be managed by this provider.
# It is a list with of hash
# :aix_attr AIX command attribute name
# :puppet_prop Puppet propertie name
# :to Method to adapt puppet property to aix command value. Optional.
# :from Method to adapt aix command value to puppet property. Optional
self.attribute_mapping = [
#:name => :name,
{:aix_attr => :pgrp, :puppet_prop => :gid,
:to => :gid_to_attr, :from => :gid_from_attr},
{:aix_attr => :id, :puppet_prop => :uid},
{:aix_attr => :groups, :puppet_prop => :groups},
{:aix_attr => :home, :puppet_prop => :home},
{:aix_attr => :shell, :puppet_prop => :shell},
{:aix_attr => :expires, :puppet_prop => :expiry,
:to => :expiry_to_attr, :from => :expiry_from_attr},
{:aix_attr => :maxage, :puppet_prop => :password_max_age},
{:aix_attr => :minage, :puppet_prop => :password_min_age},
{:aix_attr => :attributes, :puppet_prop => :attributes},
]
-
+
#--------------
# Command definition
-
+
# Return the IA module arguments based on the resource param ia_load_module
def get_ia_module_args
if @resource[:ia_load_module]
["-R", @resource[:ia_load_module].to_s]
else
[]
end
end
-
+
# List groups and Ids
def lsgroupscmd(value=@resource[:name])
[command(:lsgroup)] +
self.get_ia_module_args +
["-a", "id", value]
end
def lscmd(value=@resource[:name])
[self.class.command(:list)] + self.get_ia_module_args + [ value]
end
def lsallcmd()
lscmd("ALL")
end
def addcmd(extra_attrs = [])
# Here we use the @resource.to_hash to get the list of provided parameters
# Puppet does not call to self.<parameter>= method if it does not exists.
#
# It gets an extra list of arguments to add to the user.
[self.class.command(:add)] + self.get_ia_module_args +
self.hash2args(@resource.to_hash) +
extra_attrs + [@resource[:name]]
end
# Get modify command. Set translate=false if no mapping must be used.
# Needed for special properties like "attributes"
def modifycmd(hash = property_hash)
args = self.hash2args(hash)
return nil if args.empty?
-
+
[self.class.command(:modify)] + self.get_ia_module_args +
args + [@resource[:name]]
end
def deletecmd
[self.class.command(:delete)] + self.get_ia_module_args + [@resource[:name]]
end
#--------------
# We overwrite the create function to change the password after creation.
def create
super
# Reset the password if needed
self.password = @resource[:password] if @resource[:password]
- end
+ end
+
-
def get_arguments(key, value, mapping, objectinfo)
# In the case of attributes, return a list of key=vlaue
if key == :attributes
raise Puppet::Error, "Attributes must be a list of pairs key=value on #{@resource.class.name}[#{@resource.name}]" \
unless value and value.is_a? Hash
return value.select { |k,v| true }.map { |pair| pair.join("=") }
end
-
+
super(key, value, mapping, objectinfo)
end
-
+
# Get the groupname from its id
def self.groupname_by_id(gid)
groupname=nil
execute(lsgroupscmd("ALL")).each { |entry|
attrs = self.parse_attr_list(entry, nil)
if attrs and attrs.include? :id and gid == attrs[:id].to_i
groupname = entry.split(" ")[0]
end
}
groupname
end
# Get the groupname from its id
def groupid_by_name(groupname)
attrs = self.parse_attr_list(execute(lsgroupscmd(groupname)).split("\n")[0], nil)
attrs ? attrs[:id].to_i : nil
end
# Check that a group exists and is valid
def verify_group(value)
- if value.is_a? Integer or value.is_a? Fixnum
+ if value.is_a? Integer or value.is_a? Fixnum
groupname = self.groupname_by_id(value)
raise ArgumentError, "AIX group must be a valid existing group" unless groupname
- else
+ else
raise ArgumentError, "AIX group must be a valid existing group" unless groupid_by_name(value)
groupname = value
end
groupname
end
-
+
# The user's primary group. Can be specified numerically or by name.
def gid_to_attr(value)
verify_group(value)
end
# Get the group gid from its name
def gid_from_attr(value)
groupid_by_name(value)
end
# The expiry date for this user. Must be provided in
- # a zero padded YYYY-MM-DD HH:MM format
+ # a zero padded YYYY-MM-DD HH:MM format
def expiry_to_attr(value)
# For chuser the expires parameter is a 10-character string in the MMDDhhmmyy format
# that is,"%m%d%H%M%y"
newdate = '0'
if value.is_a? String and value!="0000-00-00"
d = DateTime.parse(value, "%Y-%m-%d %H:%M")
newdate = d.strftime("%m%d%H%M%y")
end
newdate
end
-
+
def expiry_from_attr(value)
if value =~ /(..)(..)(..)(..)(..)/
#d= DateTime.parse("20#{$5}-#{$1}-#{$2} #{$3}:#{$4}")
#expiry_date = d.strftime("%Y-%m-%d %H:%M")
#expiry_date = d.strftime("%Y-%m-%d")
expiry_date = "20#{$5}-#{$1}-#{$2}"
else
Puppet.warn("Could not convert AIX expires date '#{value}' on #{@resource.class.name}[#{@resource.name}]") \
unless value == '0'
expiry_date = :absent
end
expiry_date
end
#--------------------------------
# Getter and Setter
# When the provider is initialized, create getter/setter methods for each
# property our resource type supports.
# If setter or getter already defined it will not be overwritten
#- **password**
# The user's password, in whatever encrypted format the local machine
# requires. Be sure to enclose any value that includes a dollar sign ($)
# in single quotes ('). Requires features manages_passwords.
#
# Retrieve the password parsing directly the /etc/security/passwd
def password
password = :absent
user = @resource[:name]
f = File.open("/etc/security/passwd", 'r')
# Skip to the user
f.each { |l| break if l =~ /^#{user}:\s*$/ }
if ! f.eof?
f.each { |l|
# If there is a new user stanza, stop
- break if l =~ /^\S*:\s*$/
+ break if l =~ /^\S*:\s*$/
# If the password= entry is found, return it
if l =~ /^\s*password\s*=\s*(.*)$/
password = $1; break;
end
}
end
f.close()
return password
- end
+ end
def password=(value)
user = @resource[:name]
-
+
# Puppet execute does not support strings as input, only files.
tmpfile = Tempfile.new('puppet_#{user}_pw')
tmpfile << "#{user}:#{value}\n"
tmpfile.close()
# Options '-e', '-c', use encrypted password and clear flags
# Must receibe "user:enc_password" as input
# command, arguments = {:failonfail => true, :combine => true}
cmd = [self.class.command(:chpasswd),"-R", self.class.ia_module,
'-e', '-c', user]
begin
execute(cmd, {:failonfail => true, :combine => true, :stdinfile => tmpfile.path })
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
ensure
tmpfile.delete()
end
- end
+ end
def filter_attributes(hash)
# Return only not managed attributtes.
hash.select {
|k,v| !self.class.attribute_mapping_from.include?(k) and
!self.class.attribute_ignore.include?(k)
}.inject({}) {
|hash, array| hash[array[0]] = array[1]; hash
}
end
def attributes
filter_attributes(getosinfo(refresh = false))
end
def attributes=(attr_hash)
#self.class.validate(param, value)
param = :attributes
cmd = modifycmd({param => filter_attributes(attr_hash)})
- if cmd
+ if cmd
begin
execute(cmd)
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
end
end
end
#- **comment**
# A description of the user. Generally is a user's full name.
#def comment=(value)
#end
#
#def comment
#end
# UNSUPPORTED
#- **profile_membership**
# Whether specified roles should be treated as the only roles
# of which the user is a member or whether they should merely
# be treated as the minimum membership list. Valid values are
# `inclusive`, `minimum`.
# UNSUPPORTED
#- **profiles**
# The profiles the user has. Multiple profiles should be
# specified as an array. Requires features manages_solaris_rbac.
# UNSUPPORTED
#- **project**
# The name of the project associated with a user Requires features
# manages_solaris_rbac.
# UNSUPPORTED
#- **role_membership**
# Whether specified roles should be treated as the only roles
# of which the user is a member or whether they should merely
# be treated as the minimum membership list. Valid values are
# `inclusive`, `minimum`.
# UNSUPPORTED
#- **roles**
# The roles the user has. Multiple roles should be
# specified as an array. Requires features manages_solaris_rbac.
# UNSUPPORTED
#- **key_membership**
# Whether specified key value pairs should be treated as the only
# attributes
# of the user or whether they should merely
# be treated as the minimum list. Valid values are `inclusive`,
# `minimum`.
# UNSUPPORTED
#- **keys**
# Specify user attributes in an array of keyvalue pairs Requires features
# manages_solaris_rbac.
# UNSUPPORTED
#- **allowdupe**
# Whether to allow duplicate UIDs. Valid values are `true`, `false`.
# UNSUPPORTED
#- **auths**
# The auths the user has. Multiple auths should be
# specified as an array. Requires features manages_solaris_rbac.
# UNSUPPORTED
#- **auth_membership**
# Whether specified auths should be treated as the only auths
# of which the user is a member or whether they should merely
# be treated as the minimum membership list. Valid values are
# `inclusive`, `minimum`.
# UNSUPPORTED
end
diff --git a/lib/puppet/provider/user/hpux.rb b/lib/puppet/provider/user/hpux.rb
index 983970935..f0c8f7e8f 100644
--- a/lib/puppet/provider/user/hpux.rb
+++ b/lib/puppet/provider/user/hpux.rb
@@ -1,29 +1,31 @@
Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do
- desc "User management for hp-ux! Undocumented switch to special usermod because HP-UX regular usermod is TOO STUPID to change stuff while the user is logged in."
+ desc "User management for HP-UX. This provider uses the undocumented `-F`
+ switch to HP-UX's special `usermod` binary to work around the fact that
+ its standard `usermod` cannot make changes while the user is logged in."
defaultfor :operatingsystem => "hp-ux"
confine :operatingsystem => "hp-ux"
commands :modify => "/usr/sam/lbin/usermod.sam", :delete => "/usr/sam/lbin/userdel.sam", :add => "/usr/sbin/useradd"
options :comment, :method => :gecos
options :groups, :flag => "-G"
options :home, :flag => "-d", :method => :dir
verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
end
verify :groups, "Groups must be comma-separated" do |value|
value !~ /\s/
end
has_features :manages_homedir, :allows_duplicates
def deletecmd
super.insert(1,"-F")
end
def modifycmd(param,value)
super.insert(1,"-F")
end
end
diff --git a/lib/puppet/provider/user/ldap.rb b/lib/puppet/provider/user/ldap.rb
index 75a9667b3..2601fdb20 100644
--- a/lib/puppet/provider/user/ldap.rb
+++ b/lib/puppet/provider/user/ldap.rb
@@ -1,129 +1,129 @@
require 'puppet/provider/ldap'
Puppet::Type.type(:user).provide :ldap, :parent => Puppet::Provider::Ldap do
- desc "User management via `ldap`. This provider requires that you
- have valid values for all of the ldap-related settings,
- including `ldapbase`. You will also almost definitely need settings
- for `ldapuser` and `ldappassword`, so that your clients can write
- to ldap.
+ desc "User management via LDAP.
+
+ This provider requires that you have valid values for all of the
+ LDAP-related settings in `puppet.conf`, including `ldapbase`. You will
+ almost definitely need settings for `ldapuser` and `ldappassword` in order
+ for your clients to write to LDAP.
Note that this provider will automatically generate a UID for you if
you do not specify one, but it is a potentially expensive operation,
- as it iterates across all existing users to pick the appropriate next
- one."
+ as it iterates across all existing users to pick the appropriate next one."
confine :feature => :ldap, :false => (Puppet[:ldapuser] == "")
has_feature :manages_passwords
manages(:posixAccount, :person).at("ou=People").named_by(:uid).and.maps :name => :uid,
:password => :userPassword,
:comment => :cn,
:uid => :uidNumber,
:gid => :gidNumber,
:home => :homeDirectory,
:shell => :loginShell
# Use the last field of a space-separated array as
# the sn. LDAP requires a surname, for some stupid reason.
manager.generates(:sn).from(:cn).with do |cn|
x = 1
cn[0].split(/\s+/)[-1]
end
# Find the next uid after the current largest uid.
provider = self
manager.generates(:uidNumber).with do
largest = 500
if existing = provider.manager.search
existing.each do |hash|
next unless value = hash[:uid]
num = value[0].to_i
largest = num if num > largest
end
end
largest + 1
end
# Convert our gid to a group name, if necessary.
def gid=(value)
value = group2id(value) unless [Fixnum, Bignum].include?(value.class)
@property_hash[:gid] = value
end
# Find all groups this user is a member of in ldap.
def groups
# We want to cache the current result, so we know if we
# have to remove old values.
unless @property_hash[:groups]
unless result = group_manager.search("memberUid=#{name}")
return @property_hash[:groups] = :absent
end
return @property_hash[:groups] = result.collect { |r| r[:name] }.sort.join(",")
end
@property_hash[:groups]
end
# Manage the list of groups this user is a member of.
def groups=(values)
should = values.split(",")
if groups == :absent
is = []
else
is = groups.split(",")
end
modes = {}
[is, should].flatten.uniq.each do |group|
# Skip it when they're in both
next if is.include?(group) and should.include?(group)
# We're adding a group.
modes[group] = :add and next unless is.include?(group)
# We're removing a group.
modes[group] = :remove and next unless should.include?(group)
end
modes.each do |group, form|
self.fail "Could not find ldap group #{group}" unless ldap_group = group_manager.find(group)
current = ldap_group[:members]
if form == :add
if current.is_a?(Array) and ! current.empty?
new = current + [name]
else
new = [name]
end
else
new = current - [name]
new = :absent if new.empty?
end
group_manager.update(group, {:ensure => :present, :members => current}, {:ensure => :present, :members => new})
end
end
# Convert a gropu name to an id.
def group2id(group)
Puppet::Type.type(:group).provider(:ldap).name2id(group)
end
private
def group_manager
Puppet::Type.type(:group).provider(:ldap).manager
end
def group_properties(values)
if values.empty? or values == :absent
{:ensure => :present}
else
{:ensure => :present, :members => values}
end
end
end
diff --git a/lib/puppet/provider/user/user_role_add.rb b/lib/puppet/provider/user/user_role_add.rb
index 2377f9e65..5bed1ee59 100644
--- a/lib/puppet/provider/user/user_role_add.rb
+++ b/lib/puppet/provider/user/user_role_add.rb
@@ -1,192 +1,196 @@
require 'puppet/util/user_attr'
Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => :useradd do
- desc "User management inherits `useradd` and adds logic to manage roles on Solaris using roleadd."
+ desc "User and role management on Solaris, via `useradd` and `roleadd`."
defaultfor :operatingsystem => :solaris
commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "passwd", :role_add => "roleadd", :role_delete => "roledel", :role_modify => "rolemod"
options :home, :flag => "-d", :method => :dir
options :comment, :method => :gecos
options :groups, :flag => "-G"
options :roles, :flag => "-R"
options :auths, :flag => "-A"
options :profiles, :flag => "-P"
options :password_min_age, :flag => "-n"
options :password_max_age, :flag => "-x"
verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
end
verify :groups, "Groups must be comma-separated" do |value|
value !~ /\s/
end
has_features :manages_homedir, :allows_duplicates, :manages_solaris_rbac, :manages_passwords, :manages_password_age
#must override this to hand the keyvalue pairs
def add_properties
cmd = []
Puppet::Type.type(:user).validproperties.each do |property|
#skip the password because we can't create it with the solaris useradd
next if [:ensure, :password, :password_min_age, :password_max_age].include?(property)
# 1680 Now you can set the hashed passwords on solaris:lib/puppet/provider/user/user_role_add.rb
# the value needs to be quoted, mostly because -c might
# have spaces in it
if value = @resource.should(property) and value != ""
if property == :keys
cmd += build_keys_cmd(value)
else
cmd << flag(property) << value
end
end
end
cmd
end
def user_attributes
@user_attributes ||= UserAttr.get_attributes_by_name(@resource[:name])
end
def flush
@user_attributes = nil
end
def command(cmd)
cmd = ("role_#{cmd}").intern if is_role? or (!exists? and @resource[:ensure] == :role)
super(cmd)
end
def is_role?
user_attributes and user_attributes[:type] == "role"
end
def run(cmd, msg)
execute(cmd)
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, "Could not #{msg} #{@resource.class.name} #{@resource.name}: #{detail}"
end
def transition(type)
cmd = [command(:modify)]
cmd << "-K" << "type=#{type}"
cmd += add_properties
cmd << @resource[:name]
end
def create
if is_role?
run(transition("normal"), "transition role to")
else
run(addcmd, "create")
if cmd = passcmd
run(cmd, "change password policy for")
end
end
# added to handle case when password is specified
self.password = @resource[:password] if @resource[:password]
end
def destroy
run(deletecmd, "delete "+ (is_role? ? "role" : "user"))
end
def create_role
if exists? and !is_role?
run(transition("role"), "transition user to")
else
run(addcmd, "create role")
end
end
def roles
user_attributes[:roles] if user_attributes
end
def auths
user_attributes[:auths] if user_attributes
end
def profiles
user_attributes[:profiles] if user_attributes
end
def project
user_attributes[:project] if user_attributes
end
def managed_attributes
[:name, :type, :roles, :auths, :profiles, :project]
end
def remove_managed_attributes
managed = managed_attributes
user_attributes.select { |k,v| !managed.include?(k) }.inject({}) { |hash, array| hash[array[0]] = array[1]; hash }
end
def keys
if user_attributes
#we have to get rid of all the keys we are managing another way
remove_managed_attributes
end
end
def build_keys_cmd(keys_hash)
cmd = []
keys_hash.each do |k,v|
cmd << "-K" << "#{k}=#{v}"
end
cmd
end
def keys=(keys_hash)
run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs")
end
#Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return it
#No abstraction, all esoteric knowledge of file formats, yay
def shadow_entry
return @shadow_entry if defined? @shadow_entry
@shadow_entry = File.readlines("/etc/shadow").reject { |r| r =~ /^[^\w]/ }.collect { |l| l.chomp.split(':') }.find { |user, _| user == @resource[:name] }
end
def password
shadow_entry[1] if shadow_entry
end
def password_min_age
shadow_entry ? shadow_entry[3] : :absent
end
def password_max_age
shadow_entry ? shadow_entry[4] : :absent
end
#Read in /etc/shadow, find the line for our used and rewrite it with the new pw
#Smooth like 80 grit
def password=(cryptopw)
begin
- File.open("/etc/shadow", "r") do |shadow|
- File.open("/etc/shadow_tmp", "w", 0600) do |shadow_tmp|
+ File.open(shadow_file, "r") do |shadow|
+ File.open("#{shadow_file}_tmp", "w", 0600) do |shadow_tmp|
while line = shadow.gets
line_arr = line.split(':')
if line_arr[0] == @resource[:name]
line_arr[1] = cryptopw
+ line_arr[2] = Time.now().to_i / 86400
line = line_arr.join(':')
end
shadow_tmp.print line
end
end
end
- File.rename("/etc/shadow_tmp", "/etc/shadow")
+ File.rename("#{shadow_file}_tmp", shadow_file)
rescue => detail
fail "Could not write temporary shadow file: #{detail}"
ensure
# Make sure this *always* gets deleted
- File.unlink("/etc/shadow_tmp") if File.exist?("/etc/shadow_tmp")
+ File.unlink("#{shadow_file}_tmp") if File.exist?("#{shadow_file}_tmp")
end
end
-end
+ private
+
+ def shadow_file; '/etc/shadow'; end
+end
diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb
index b87971738..e3749057f 100644
--- a/lib/puppet/provider/user/useradd.rb
+++ b/lib/puppet/provider/user/useradd.rb
@@ -1,114 +1,116 @@
require 'puppet/provider/nameservice/objectadd'
Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameService::ObjectAdd do
- desc "User management via `useradd` and its ilk. Note that you will need to install the `Shadow Password` Ruby library often known as ruby-libshadow to manage user passwords."
+ desc "User management via `useradd` and its ilk. Note that you will need to
+ install Ruby's shadow password library (often known as `ruby-libshadow`)
+ if you wish to manage user passwords."
commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "chage"
options :home, :flag => "-d", :method => :dir
options :comment, :method => :gecos
options :groups, :flag => "-G"
options :password_min_age, :flag => "-m"
options :password_max_age, :flag => "-M"
verify :gid, "GID must be an integer" do |value|
value.is_a? Integer
end
verify :groups, "Groups must be comma-separated" do |value|
value !~ /\s/
end
has_features :manages_homedir, :allows_duplicates, :manages_expiry, :system_users
has_features :manages_passwords, :manages_password_age if Puppet.features.libshadow?
def check_allow_dup
@resource.allowdupe? ? ["-o"] : []
end
def check_manage_home
cmd = []
if @resource.managehome?
cmd << "-m"
elsif %w{Fedora RedHat CentOS OEL OVS}.include?(Facter.value("operatingsystem"))
cmd << "-M"
end
cmd
end
def check_manage_expiry
cmd = []
if @resource[:expiry]
cmd << "-e #{@resource[:expiry]}"
end
cmd
end
def check_system_users
@resource.system? ? ["-r"] : []
end
def add_properties
cmd = []
Puppet::Type.type(:user).validproperties.each do |property|
next if property == :ensure
next if property.to_s =~ /password_.+_age/
# the value needs to be quoted, mostly because -c might
# have spaces in it
if value = @resource.should(property) and value != ""
cmd << flag(property) << value
end
end
cmd
end
def addcmd
cmd = [command(:add)]
cmd += add_properties
cmd += check_allow_dup
cmd += check_manage_home
cmd += check_manage_expiry
cmd += check_system_users
cmd << @resource[:name]
end
def passcmd
age_limits = [:password_min_age, :password_max_age].select { |property| @resource.should(property) }
if age_limits.empty?
nil
else
[command(:password),age_limits.collect { |property| [flag(property), @resource.should(property)]}, @resource[:name]].flatten
end
end
def password_min_age
if Puppet.features.libshadow?
if ent = Shadow::Passwd.getspnam(@resource.name)
return ent.sp_min
end
end
:absent
end
def password_max_age
if Puppet.features.libshadow?
if ent = Shadow::Passwd.getspnam(@resource.name)
return ent.sp_max
end
end
:absent
end
# Retrieve the password using the Shadow Password library
def password
if Puppet.features.libshadow?
if ent = Shadow::Passwd.getspnam(@resource.name)
return ent.sp_pwdp
end
end
:absent
end
end
diff --git a/lib/puppet/provider/user/windows_adsi.rb b/lib/puppet/provider/user/windows_adsi.rb
index 1470e17b2..6b0a9bce7 100644
--- a/lib/puppet/provider/user/windows_adsi.rb
+++ b/lib/puppet/provider/user/windows_adsi.rb
@@ -1,88 +1,87 @@
require 'puppet/util/adsi'
Puppet::Type.type(:user).provide :windows_adsi do
- desc "User management for Windows"
+ desc "User management for Windows."
defaultfor :operatingsystem => :windows
- confine :operatingsystem => :windows
- confine :feature => :microsoft_windows
+ confine :operatingsystem => :windows
has_features :manages_homedir, :manages_passwords
def user
@user ||= Puppet::Util::ADSI::User.new(@resource[:name])
end
def groups
user.groups.join(',')
end
def groups=(groups)
user.set_groups(groups, @resource[:membership] == :minimum)
end
def create
@user = Puppet::Util::ADSI::User.create(@resource[:name])
@user.commit
[:comment, :home, :groups].each do |prop|
send("#{prop}=", @resource[prop]) if @resource[prop]
end
end
def exists?
Puppet::Util::ADSI::User.exists?(@resource[:name])
end
def delete
Puppet::Util::ADSI::User.delete(@resource[:name])
end
# Only flush if we created or modified a user, not deleted
def flush
@user.commit if @user
end
def comment
user['Description']
end
def comment=(value)
user['Description'] = value
end
def home
user['HomeDirectory']
end
def home=(value)
user['HomeDirectory'] = value
end
def password
user.password_is?( @resource[:password] ) ? @resource[:password] : :absent
end
def password=(value)
user.password = value
end
def uid
Puppet::Util::ADSI.sid_for_account(@resource[:name])
end
def uid=(value)
fail "uid is read-only"
end
[:gid, :shell].each do |prop|
define_method(prop) { nil }
define_method("#{prop}=") do |v|
fail "No support for managing property #{prop} of user #{@resource[:name]} on Windows"
end
end
def self.instances
Puppet::Util::ADSI::User.map { |u| new(:ensure => :present, :name => u.name) }
end
end
diff --git a/lib/puppet/reference/configuration.rb b/lib/puppet/reference/configuration.rb
index 18efb6fe7..c1e225367 100644
--- a/lib/puppet/reference/configuration.rb
+++ b/lib/puppet/reference/configuration.rb
@@ -1,69 +1,69 @@
config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc => "A reference for all configuration parameters") do
docs = {}
Puppet.settings.each do |name, object|
docs[name] = object
end
str = ""
docs.sort { |a, b|
a[0].to_s <=> b[0].to_s
}.each do |name, object|
# Make each name an anchor
header = name.to_s
- str += h(header, 3)
+ str << markdown_header(header, 3)
# Print the doc string itself
begin
- str += object.desc.gsub(/\n/, " ")
+ str << object.desc.gsub(/\n/, " ")
rescue => detail
puts detail.backtrace
puts detail
end
- str += "\n\n"
+ str << "\n\n"
# Now print the data about the item.
- str += ""
+ str << ""
val = object.default
if name.to_s == "vardir"
val = "/var/lib/puppet"
elsif name.to_s == "confdir"
val = "/etc/puppet"
end
# Leave out the section information; it was apparently confusing people.
- #str += "- **Section**: #{object.section}\n"
+ #str << "- **Section**: #{object.section}\n"
unless val == ""
- str += "- *Default*: #{val}\n"
+ str << "- *Default*: #{val}\n"
end
- str += "\n"
+ str << "\n"
end
return str
end
config.header = <<EOT
## Configuration Settings
* Each of these settings can be specified in `puppet.conf` or on the
command line.
* When using boolean settings on the command line, use `--setting` and
`--no-setting` instead of `--setting (true|false)`.
* Settings can be interpolated as `$variables` in other settings; `$environment`
is special, in that puppet master will interpolate each agent node's
environment instead of its own.
* Multiple values should be specified as comma-separated lists; multiple
directories should be separated with the system path separator (usually
a colon).
* Settings that take a single file or directory can optionally set the owner,
group, and mode for their value: `rundir = $vardir/run { owner = puppet,
group = puppet, mode = 644 }`
* The Puppet executables will ignore any setting that isn't relevant to
their function.
See the [configuration guide][confguide] for more details.
[confguide]: http://docs.puppetlabs.com/guides/configuring.html
* * *
EOT
diff --git a/lib/puppet/reference/indirection.rb b/lib/puppet/reference/indirection.rb
index e5b076508..af1440d1e 100644
--- a/lib/puppet/reference/indirection.rb
+++ b/lib/puppet/reference/indirection.rb
@@ -1,33 +1,32 @@
require 'puppet/indirector/indirection'
require 'puppet/util/checksums'
require 'puppet/file_serving/content'
require 'puppet/file_serving/metadata'
reference = Puppet::Util::Reference.newreference :indirection, :doc => "Indirection types and their terminus classes" do
text = ""
Puppet::Indirector::Indirection.instances.sort { |a,b| a.to_s <=> b.to_s }.each do |indirection|
ind = Puppet::Indirector::Indirection.instance(indirection)
name = indirection.to_s.capitalize
- text += "## " + indirection.to_s + "\n\n"
+ text << "## " + indirection.to_s + "\n\n"
- text += ind.doc + "\n\n"
+ text << ind.doc + "\n\n"
Puppet::Indirector::Terminus.terminus_classes(ind.name).sort { |a,b| a.to_s <=> b.to_s }.each do |terminus|
- text += "### " + terminus.to_s + "\n\n"
-
+ terminus_name = terminus.to_s
term_class = Puppet::Indirector::Terminus.terminus_class(ind.name, terminus)
-
- text += Puppet::Util::Docs.scrub(term_class.doc) + "\n\n"
+ terminus_doc = Puppet::Util::Docs.scrub(term_class.doc)
+ text << markdown_definitionlist(terminus_name, terminus_doc)
end
end
text
end
reference.header = "This is the list of all indirections, their associated terminus classes, and how you select between them.
In general, the appropriate terminus class is selected by the application for you (e.g., `puppet agent` would always use the `rest`
terminus for most of its indirected classes), but some classes are tunable via normal settings. These will have `terminus setting` documentation listed with them.
"
diff --git a/lib/puppet/reference/metaparameter.rb b/lib/puppet/reference/metaparameter.rb
index 3c4c08701..9235d3d26 100644
--- a/lib/puppet/reference/metaparameter.rb
+++ b/lib/puppet/reference/metaparameter.rb
@@ -1,41 +1,43 @@
metaparameter = Puppet::Util::Reference.newreference :metaparameter, :doc => "All Puppet metaparameters and all their details" do
types = {}
Puppet::Type.loadall
Puppet::Type.eachtype { |type|
next if type.name == :puppet
next if type.name == :component
types[type.name] = type
}
str = %{
# Metaparameters
Metaparameters are parameters that work with any resource type; they are part of the
Puppet framework itself rather than being part of the implementation of any
given instance. Thus, any defined metaparameter can be used with any instance
in your manifest, including defined components.
## Available Metaparameters
}
begin
params = []
Puppet::Type.eachmetaparam { |param|
params << param
}
params.sort { |a,b|
a.to_s <=> b.to_s
}.each { |param|
- str += paramwrap(param.to_s, scrub(Puppet::Type.metaparamdoc(param)), :level => 3)
+ str << markdown_header(param.to_s, 3)
+ str << scrub(Puppet::Type.metaparamdoc(param))
+ str << "\n\n"
}
rescue => detail
puts detail.backtrace
puts "incorrect metaparams: #{detail}"
exit(1)
end
str
end
diff --git a/lib/puppet/reference/network.rb b/lib/puppet/reference/network.rb
index fda7931fb..ee8fea07e 100644
--- a/lib/puppet/reference/network.rb
+++ b/lib/puppet/reference/network.rb
@@ -1,39 +1,39 @@
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 += h(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"
+ 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/reference/providers.rb b/lib/puppet/reference/providers.rb
index c85ad23ab..576b00bcb 100644
--- a/lib/puppet/reference/providers.rb
+++ b/lib/puppet/reference/providers.rb
@@ -1,123 +1,123 @@
# This doesn't get stored in trac, since it changes every time.
providers = Puppet::Util::Reference.newreference :providers, :title => "Provider Suitability Report", :depth => 1, :dynamic => true, :doc => "Which providers are valid for this machine" do
types = []
Puppet::Type.loadall
Puppet::Type.eachtype do |klass|
next unless klass.providers.length > 0
types << klass
end
types.sort! { |a,b| a.name.to_s <=> b.name.to_s }
command_line = Puppet::Util::CommandLine.new
types.reject! { |type| ! command_line.args.include?(type.name.to_s) } unless command_line.args.empty?
ret = "Details about this host:\n\n"
# Throw some facts in there, so we know where the report is from.
["Ruby Version", "Puppet Version", "Operating System", "Operating System Release"].each do |label|
name = label.gsub(/\s+/, '')
value = Facter.value(name)
- ret += option(label, value)
+ ret << option(label, value)
end
- ret += "\n"
+ ret << "\n"
count = 1
# Produce output for each type.
types.each do |type|
features = type.features
- ret += "\n" # add a trailing newline
+ ret << "\n" # add a trailing newline
# Now build up a table of provider suitability.
headers = %w{Provider Suitable?} + features.collect { |f| f.to_s }.sort
table_data = {}
functional = false
notes = []
begin
default = type.defaultprovider.name
rescue Puppet::DevError
default = "none"
end
type.providers.sort { |a,b| a.to_s <=> b.to_s }.each do |pname|
data = []
table_data[pname] = data
provider = type.provider(pname)
# Add the suitability note
if missing = provider.suitable?(false) and missing.empty?
data << "*X*"
suit = true
functional = true
else
data << "[#{count}]_" # A pointer to the appropriate footnote
suit = false
end
# Add a footnote with the details about why this provider is unsuitable, if that's the case
unless suit
details = ".. [#{count}]\n"
missing.each do |test, values|
case test
when :exists
- details += " - Missing files #{values.join(", ")}\n"
+ details << " - Missing files #{values.join(", ")}\n"
when :variable
values.each do |name, facts|
if Puppet.settings.valid?(name)
- details += " - Setting #{name} (currently #{Puppet.settings.value(name).inspect}) not in list #{facts.join(", ")}\n"
+ details << " - Setting #{name} (currently #{Puppet.settings.value(name).inspect}) not in list #{facts.join(", ")}\n"
else
- details += " - Fact #{name} (currently #{Facter.value(name).inspect}) not in list #{facts.join(", ")}\n"
+ details << " - Fact #{name} (currently #{Facter.value(name).inspect}) not in list #{facts.join(", ")}\n"
end
end
when :true
- details += " - Got #{values} true tests that should have been false\n"
+ details << " - Got #{values} true tests that should have been false\n"
when :false
- details += " - Got #{values} false tests that should have been true\n"
+ details << " - Got #{values} false tests that should have been true\n"
when :feature
- details += " - Missing features #{values.collect { |f| f.to_s }.join(",")}\n"
+ details << " - Missing features #{values.collect { |f| f.to_s }.join(",")}\n"
end
end
notes << details
count += 1
end
# Add a note for every feature
features.each do |feature|
if provider.features.include?(feature)
data << "*X*"
else
data << ""
end
end
end
- ret += h(type.name.to_s + "_", 2)
+ ret << markdown_header(type.name.to_s + "_", 2)
- ret += "[#{type.name}](#{"http://docs.puppetlabs.com/references/stable/type.html##{type.name}"})\n\n"
- ret += option("Default provider", default)
- ret += doctable(headers, table_data)
+ ret << "[#{type.name}](#{"http://docs.puppetlabs.com/references/stable/type.html##{type.name}"})\n\n"
+ ret << option("Default provider", default)
+ ret << doctable(headers, table_data)
notes.each do |note|
- ret += note + "\n"
+ ret << note + "\n"
end
- ret += "\n"
+ ret << "\n"
end
- ret += "\n"
+ ret << "\n"
ret
end
providers.header = "
Puppet resource types are usually backed by multiple implementations called `providers`,
which handle variance between platforms and tools.
Different providers are suitable or unsuitable on different platforms based on things
like the presence of a given tool.
Here are all of the provider-backed types and their different providers. Any unmentioned
types do not use providers yet.
"
diff --git a/lib/puppet/reference/type.rb b/lib/puppet/reference/type.rb
index b423387e9..87aed435c 100644
--- a/lib/puppet/reference/type.rb
+++ b/lib/puppet/reference/type.rb
@@ -1,113 +1,116 @@
type = Puppet::Util::Reference.newreference :type, :doc => "All Puppet resource types and all their details" do
types = {}
Puppet::Type.loadall
Puppet::Type.eachtype { |type|
next if type.name == :puppet
next if type.name == :component
next if type.name == :whit
types[type.name] = type
}
str = %{
## Resource Types
- The *namevar* is the parameter used to uniquely identify a type instance.
This is the parameter that gets assigned when a string is provided before
the colon in a type declaration. In general, only developers will need to
worry about which parameter is the `namevar`.
In the following code:
file { "/etc/passwd":
owner => root,
group => root,
- mode => 644
+ mode => 644
}
`/etc/passwd` is considered the title of the file object (used for things like
dependency handling), and because `path` is the namevar for `file`, that
string is assigned to the `path` parameter.
- *Parameters* determine the specific configuration of the instance. They either
directly modify the system (internally, these are called properties) or they affect
how the instance behaves (e.g., adding a search path for `exec` instances or determining recursion on `file` instances).
- *Providers* provide low-level functionality for a given resource type. This is
usually in the form of calling out to external commands.
When required binaries are specified for providers, fully qualifed paths
indicate that the binary must exist at that specific path and unqualified
binaries indicate that Puppet will search for the binary using the shell
path.
- *Features* are abilities that some providers might not support. You can use the list
of supported features to determine how a given provider can be used.
Resource types define features they can use, and providers can be tested to see
which features they provide.
}
types.sort { |a,b|
a.to_s <=> b.to_s
}.each { |name,type|
- str += "
+ str << "
----------------
"
- str += h(name, 3)
- str += scrub(type.doc) + "\n\n"
+ str << markdown_header(name, 3)
+ str << scrub(type.doc) + "\n\n"
# Handle the feature docs.
if featuredocs = type.featuredocs
- str += h("Features", 4)
- str += featuredocs
+ str << markdown_header("Features", 4)
+ str << featuredocs
end
docs = {}
type.validproperties.sort { |a,b|
a.to_s <=> b.to_s
}.reject { |sname|
property = type.propertybyname(sname)
property.nodoc
}.each { |sname|
property = type.propertybyname(sname)
raise "Could not retrieve property #{sname} on type #{type.name}" unless property
doc = nil
unless doc = property.doc
$stderr.puts "No docs for #{type}[#{sname}]"
next
end
doc = doc.dup
tmp = doc
tmp = scrub(tmp)
docs[sname] = tmp
}
- str += h("Parameters", 4) + "\n"
+ str << markdown_header("Parameters", 4) + "\n"
type.parameters.sort { |a,b|
a.to_s <=> b.to_s
}.each { |name,param|
#docs[name] = indent(scrub(type.paramdoc(name)), $tab)
docs[name] = scrub(type.paramdoc(name))
}
additional_key_attributes = type.key_attributes - [:name]
docs.sort { |a, b|
a[0].to_s <=> b[0].to_s
}.each { |name, doc|
- str += paramwrap(name, doc, :namevar => additional_key_attributes.include?(name))
+ if additional_key_attributes.include?(name)
+ doc = "(**Namevar:** If omitted, this parameter's value defaults to the resource's title.)\n\n" + doc
+ end
+ str << markdown_definitionlist(name, doc)
}
- str += "\n"
+ str << "\n"
}
str
end
diff --git a/lib/puppet/ssl/certificate.rb b/lib/puppet/ssl/certificate.rb
index d57ac1a06..719a741a7 100644
--- a/lib/puppet/ssl/certificate.rb
+++ b/lib/puppet/ssl/certificate.rb
@@ -1,40 +1,40 @@
require 'puppet/ssl/base'
# Manage certificates themselves. This class has no
# 'generate' method because the CA is responsible
# for turning CSRs into certificates; we can only
# retrieve them from the CA (or not, as is often
# the case).
class Puppet::SSL::Certificate < Puppet::SSL::Base
# This is defined from the base class
wraps OpenSSL::X509::Certificate
extend Puppet::Indirector
indirects :certificate, :terminus_class => :file
# Convert a string into an instance.
def self.from_s(string)
instance = wrapped_class.new(string)
name = instance.subject.to_s.sub(/\/CN=/i, '').downcase
result = new(name)
result.content = instance
result
end
# Because of how the format handler class is included, this
# can't be in the base class.
def self.supported_formats
[:s]
end
- def alternate_names
+ def subject_alt_names
alts = content.extensions.find{|ext| ext.oid == "subjectAltName"}
return [] unless alts
- alts.value.split(/,\s+/).map{|al| al.sub(/^DNS:/,'')}
+ alts.value.split(/\s*,\s*/)
end
def expiration
return nil unless content
content.not_after
end
end
diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb
index a4cbaf78a..179acd998 100644
--- a/lib/puppet/ssl/certificate_authority.rb
+++ b/lib/puppet/ssl/certificate_authority.rb
@@ -1,286 +1,362 @@
require 'monitor'
require 'puppet/ssl/host'
require 'puppet/ssl/certificate_request'
# The class that knows how to sign certificates. It creates
# a 'special' SSL::Host whose name is 'ca', thus indicating
# that, well, it's the CA. There's some magic in the
# indirector/ssl_file terminus base class that does that
# for us.
# This class mostly just signs certs for us, but
# it can also be seen as a general interface into all of the
# SSL stuff.
class Puppet::SSL::CertificateAuthority
+ # We will only sign extensions on this whitelist, ever. Any CSR with a
+ # requested extension that we don't recognize is rejected, against the risk
+ # that it will introduce some security issue through our ignorance of it.
+ #
+ # Adding an extension to this whitelist simply means we will consider it
+ # further, not that we will always accept a certificate with an extension
+ # requested on this list.
+ RequestExtensionWhitelist = %w{subjectAltName}
+
require 'puppet/ssl/certificate_factory'
require 'puppet/ssl/inventory'
require 'puppet/ssl/certificate_revocation_list'
require 'puppet/ssl/certificate_authority/interface'
require 'puppet/network/authstore'
extend MonitorMixin
class CertificateVerificationError < RuntimeError
attr_accessor :error_code
def initialize(code)
@error_code = code
end
end
def self.singleton_instance
synchronize do
@singleton_instance ||= new
end
end
+ class CertificateSigningError < RuntimeError
+ attr_accessor :host
+
+ def initialize(host)
+ @host = host
+ end
+ end
+
def self.ca?
return false unless Puppet[:ca]
return false unless Puppet.run_mode.master?
true
end
# If this process can function as a CA, then return a singleton
# instance.
def self.instance
return nil unless ca?
singleton_instance
end
attr_reader :name, :host
# Create and run an applicator. I wanted to build an interface where you could do
# something like 'ca.apply(:generate).to(:all) but I don't think it's really possible.
def apply(method, options)
raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all" unless options[:to]
applier = Interface.new(method, options)
-
applier.apply(self)
end
# If autosign is configured, then autosign all CSRs that match our configuration.
def autosign
return unless auto = autosign?
store = nil
store = autosign_store(auto) if auto != true
Puppet::SSL::CertificateRequest.indirection.search("*").each do |csr|
sign(csr.name) if auto == true or store.allowed?(csr.name, "127.1.1.1")
end
end
# Do we autosign? This returns true, false, or a filename.
def autosign?
auto = Puppet[:autosign]
return false if ['false', false].include?(auto)
return true if ['true', true].include?(auto)
raise ArgumentError, "The autosign configuration '#{auto}' must be a fully qualified file" unless auto =~ /^\//
FileTest.exist?(auto) && auto
end
# Create an AuthStore for autosigning.
def autosign_store(file)
auth = Puppet::Network::AuthStore.new
File.readlines(file).each do |line|
next if line =~ /^\s*#/
next if line =~ /^\s*$/
auth.allow(line.chomp)
end
auth
end
# Retrieve (or create, if necessary) the certificate revocation list.
def crl
unless defined?(@crl)
unless @crl = Puppet::SSL::CertificateRevocationList.indirection.find(Puppet::SSL::CA_NAME)
@crl = Puppet::SSL::CertificateRevocationList.new(Puppet::SSL::CA_NAME)
@crl.generate(host.certificate.content, host.key.content)
Puppet::SSL::CertificateRevocationList.indirection.save(@crl)
end
end
@crl
end
# Delegate this to our Host class.
def destroy(name)
Puppet::SSL::Host.destroy(name)
end
# Generate a new certificate.
- def generate(name)
+ def generate(name, options = {})
raise ArgumentError, "A Certificate already exists for #{name}" if Puppet::SSL::Certificate.indirection.find(name)
host = Puppet::SSL::Host.new(name)
- host.generate_certificate_request
+ # Pass on any requested subjectAltName field.
+ san = options[:dns_alt_names]
- sign(name)
+ host = Puppet::SSL::Host.new(name)
+ host.generate_certificate_request(:dns_alt_names => san)
+ sign(name, !!san)
end
# Generate our CA certificate.
def generate_ca_certificate
generate_password unless password?
host.generate_key unless host.key
- # Create a new cert request. We do this
- # specially, because we don't want to actually
- # save the request anywhere.
+ # Create a new cert request. We do this specially, because we don't want
+ # to actually save the request anywhere.
request = Puppet::SSL::CertificateRequest.new(host.name)
+
+ # We deliberately do not put any subjectAltName in here: the CA
+ # certificate absolutely does not need them. --daniel 2011-10-13
request.generate(host.key)
# Create a self-signed certificate.
- @certificate = sign(host.name, :ca, request)
+ @certificate = sign(host.name, false, request)
# And make sure we initialize our CRL.
crl
end
def initialize
Puppet.settings.use :main, :ssl, :ca
@name = Puppet[:certname]
@host = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name)
setup
end
# Retrieve (or create, if necessary) our inventory manager.
def inventory
@inventory ||= Puppet::SSL::Inventory.new
end
# Generate a new password for the CA.
def generate_password
pass = ""
20.times { pass += (rand(74) + 48).chr }
begin
Puppet.settings.write(:capass) { |f| f.print pass }
rescue Errno::EACCES => detail
raise Puppet::Error, "Could not write CA password: #{detail}"
end
@password = pass
pass
end
# List all signed certificates.
def list
Puppet::SSL::Certificate.indirection.search("*").collect { |c| c.name }
end
# Read the next serial from the serial file, and increment the
# file so this one is considered used.
def next_serial
serial = nil
# This is slightly odd. If the file doesn't exist, our readwritelock creates
# it, but with a mode we can't actually read in some cases. So, use
# a default before the lock.
serial = 0x1 unless FileTest.exist?(Puppet[:serial])
Puppet.settings.readwritelock(:serial) { |f|
serial ||= File.read(Puppet.settings[:serial]).chomp.hex if FileTest.exist?(Puppet[:serial])
# We store the next valid serial, not the one we just used.
f << "%04X" % (serial + 1)
}
serial
end
# Does the password file exist?
def password?
FileTest.exist? Puppet[:capass]
end
# Print a given host's certificate as text.
def print(name)
(cert = Puppet::SSL::Certificate.indirection.find(name)) ? cert.to_text : nil
end
# Revoke a given certificate.
def revoke(name)
raise ArgumentError, "Cannot revoke certificates when the CRL is disabled" unless crl
if cert = Puppet::SSL::Certificate.indirection.find(name)
serial = cert.content.serial
elsif ! serial = inventory.serial(name)
raise ArgumentError, "Could not find a serial number for #{name}"
end
crl.revoke(serial, host.key.content)
end
# This initializes our CA so it actually works. This should be a private
# method, except that you can't any-instance stub private methods, which is
# *awesome*. This method only really exists to provide a stub-point during
# testing.
def setup
generate_ca_certificate unless @host.certificate
end
# Sign a given certificate request.
- def sign(hostname, cert_type = :server, self_signing_csr = nil)
+ def sign(hostname, allow_dns_alt_names = false, self_signing_csr = nil)
# This is a self-signed certificate
if self_signing_csr
+ # # This is a self-signed certificate, which is for the CA. Since this
+ # # forces the certificate to be self-signed, anyone who manages to trick
+ # # the system into going through this path gets a certificate they could
+ # # generate anyway. There should be no security risk from that.
csr = self_signing_csr
+ cert_type = :ca
issuer = csr.content
else
+ allow_dns_alt_names = true if hostname == Puppet[:certname].downcase
unless csr = Puppet::SSL::CertificateRequest.indirection.find(hostname)
raise ArgumentError, "Could not find certificate request for #{hostname}"
end
+
+ cert_type = :server
issuer = host.certificate.content
+
+ # Make sure that the CSR conforms to our internal signing policies.
+ # This will raise if the CSR doesn't conform, but just in case...
+ check_internal_signing_policies(hostname, csr, allow_dns_alt_names) or
+ raise CertificateSigningError.new(hostname), "CSR had an unknown failure checking internal signing policies, will not sign!"
end
cert = Puppet::SSL::Certificate.new(hostname)
- cert.content = Puppet::SSL::CertificateFactory.new(cert_type, csr.content, issuer, next_serial).result
+ cert.content = Puppet::SSL::CertificateFactory.
+ build(cert_type, csr, issuer, next_serial)
cert.content.sign(host.key.content, OpenSSL::Digest::SHA1.new)
Puppet.notice "Signed certificate request for #{hostname}"
# Add the cert to the inventory before we save it, since
# otherwise we could end up with it being duplicated, if
# this is the first time we build the inventory file.
inventory.add(cert)
# Save the now-signed cert. This should get routed correctly depending
# on the certificate type.
Puppet::SSL::Certificate.indirection.save(cert)
# And remove the CSR if this wasn't self signed.
Puppet::SSL::CertificateRequest.indirection.destroy(csr.name) unless self_signing_csr
cert
end
+ def check_internal_signing_policies(hostname, csr, allow_dns_alt_names)
+ # Reject unknown request extensions.
+ unknown_req = csr.request_extensions.
+ reject {|x| RequestExtensionWhitelist.include? x["oid"] }
+
+ if unknown_req and not unknown_req.empty?
+ names = unknown_req.map {|x| x["oid"] }.sort.uniq.join(", ")
+ raise CertificateSigningError.new(hostname), "CSR has request extensions that are not permitted: #{names}"
+ end
+
+ # Wildcards: we don't allow 'em at any point.
+ #
+ # The stringification here makes the content visible, and saves us having
+ # to scrobble through the content of the CSR subject field to make sure it
+ # is what we expect where we expect it.
+ if csr.content.subject.to_s.include? '*'
+ raise CertificateSigningError.new(hostname), "CSR subject contains a wildcard, which is not allowed: #{csr.content.subject.to_s}"
+ end
+
+ unless csr.subject_alt_names.empty?
+ # If you alt names are allowed, they are required. Otherwise they are
+ # disallowed. Self-signed certs are implicitly trusted, however.
+ unless allow_dns_alt_names
+ raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' contains subject alternative names (#{csr.subject_alt_names.join(', ')}), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{csr.name}` to sign this request."
+ end
+
+ # If subjectAltNames are present, validate that they are only for DNS
+ # labels, not any other kind.
+ unless csr.subject_alt_names.all? {|x| x =~ /^DNS:/ }
+ raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' contains a subjectAltName outside the DNS label space: #{csr.subject_alt_names.join(', ')}. To continue, this CSR needs to be cleaned."
+ end
+
+ # Check for wildcards in the subjectAltName fields too.
+ if csr.subject_alt_names.any? {|x| x.include? '*' }
+ raise CertificateSigningError.new(hostname), "CSR '#{csr.name}' subjectAltName contains a wildcard, which is not allowed: #{csr.subject_alt_names.join(', ')} To continue, this CSR needs to be cleaned."
+ end
+ end
+
+ return true # good enough for us!
+ end
+
# Verify a given host's certificate.
def verify(name)
unless cert = Puppet::SSL::Certificate.indirection.find(name)
raise ArgumentError, "Could not find a certificate for #{name}"
end
store = OpenSSL::X509::Store.new
store.add_file Puppet[:cacert]
store.add_crl crl.content if self.crl
store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
raise CertificateVerificationError.new(store.error), store.error_string unless store.verify(cert.content)
end
def fingerprint(name, md = :MD5)
unless cert = Puppet::SSL::Certificate.indirection.find(name) || Puppet::SSL::CertificateRequest.indirection.find(name)
raise ArgumentError, "Could not find a certificate or csr for #{name}"
end
cert.fingerprint(md)
end
# List the waiting certificate requests.
def waiting?
Puppet::SSL::CertificateRequest.indirection.search("*").collect { |r| r.name }
end
end
diff --git a/lib/puppet/ssl/certificate_authority/interface.rb b/lib/puppet/ssl/certificate_authority/interface.rb
index f73eff5f3..1e4e06e30 100644
--- a/lib/puppet/ssl/certificate_authority/interface.rb
+++ b/lib/puppet/ssl/certificate_authority/interface.rb
@@ -1,134 +1,179 @@
# This class is basically a hidden class that knows how to act
# on the CA. It's only used by the 'puppetca' executable, and its
# job is to provide a CLI-like interface to the CA class.
module Puppet
module SSL
class CertificateAuthority
class Interface
INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint]
class InterfaceError < ArgumentError; end
- attr_reader :method, :subjects, :digest
+ attr_reader :method, :subjects, :digest, :options
# Actually perform the work.
def apply(ca)
unless subjects or method == :list
raise ArgumentError, "You must provide hosts or :all when using #{method}"
end
begin
return send(method, ca) if respond_to?(method)
(subjects == :all ? ca.list : subjects).each do |host|
ca.send(method, host)
end
rescue InterfaceError
raise
rescue => detail
puts detail.backtrace if Puppet[:trace]
Puppet.err "Could not call #{method}: #{detail}"
end
end
def generate(ca)
raise InterfaceError, "It makes no sense to generate all hosts; you must specify a list" if subjects == :all
subjects.each do |host|
- ca.generate(host)
+ ca.generate(host, options)
end
end
def initialize(method, options)
self.method = method
- self.subjects = options[:to]
- @digest = options[:digest] || :MD5
+ self.subjects = options.delete(:to)
+ @digest = options.delete(:digest) || :MD5
+ @options = options
end
# List the hosts.
def list(ca)
- unless subjects
- puts ca.waiting?.join("\n")
- return nil
- end
-
signed = ca.list
requests = ca.waiting?
- if subjects == :all
+ case subjects
+ when :all
hosts = [signed, requests].flatten
- elsif subjects == :signed
+ when :signed
hosts = signed.flatten
+ when nil
+ hosts = requests
else
hosts = subjects
end
+ certs = {:signed => {}, :invalid => {}, :request => {}}
+
+ return if hosts.empty?
+
hosts.uniq.sort.each do |host|
- invalid = false
begin
ca.verify(host) unless requests.include?(host)
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => details
- invalid = details.to_s
+ verify_error = details.to_s
end
- if not invalid and signed.include?(host)
- puts "+ #{host} (#{ca.fingerprint(host, @digest)})"
- elsif invalid
- puts "- #{host} (#{ca.fingerprint(host, @digest)}) (#{invalid})"
+
+ if verify_error
+ cert = Puppet::SSL::Certificate.indirection.find(host)
+ certs[:invalid][host] = [cert, verify_error]
+ elsif signed.include?(host)
+ cert = Puppet::SSL::Certificate.indirection.find(host)
+ certs[:signed][host] = cert
else
- puts "#{host} (#{ca.fingerprint(host, @digest)})"
+ req = Puppet::SSL::CertificateRequest.indirection.find(host)
+ certs[:request][host] = req
end
end
+
+ names = certs.values.map(&:keys).flatten
+
+ name_width = names.sort_by(&:length).last.length rescue 0
+
+ output = [:request, :signed, :invalid].map do |type|
+ next if certs[type].empty?
+
+ certs[type].map do |host,info|
+ format_host(ca, host, type, info, name_width)
+ end
+ end.flatten.compact.sort.join("\n")
+
+ puts output
+ end
+
+ def format_host(ca, host, type, info, width)
+ certish, verify_error = info
+ alt_names = case type
+ when :signed
+ certish.subject_alt_names
+ when :request
+ certish.subject_alt_names
+ else
+ []
+ end
+
+ alt_names.delete(host)
+
+ alt_str = "(alt names: #{alt_names.join(', ')})" unless alt_names.empty?
+
+ glyph = {:signed => '+', :request => ' ', :invalid => '-'}[type]
+
+ name = host.ljust(width)
+ fingerprint = "(#{ca.fingerprint(host, @digest)})"
+
+ explanation = "(#{verify_error})" if verify_error
+
+ [glyph, name, fingerprint, alt_str, explanation].compact.join(' ')
end
# Set the method to apply.
def method=(method)
raise ArgumentError, "Invalid method #{method} to apply" unless INTERFACE_METHODS.include?(method)
@method = method
end
# Print certificate information.
def print(ca)
(subjects == :all ? ca.list : subjects).each do |host|
if value = ca.print(host)
puts value
else
Puppet.err "Could not find certificate for #{host}"
end
end
end
# Print certificate information.
def fingerprint(ca)
(subjects == :all ? ca.list + ca.waiting?: subjects).each do |host|
if value = ca.fingerprint(host, @digest)
puts "#{host} #{value}"
else
Puppet.err "Could not find certificate for #{host}"
end
end
end
# Sign a given certificate.
def sign(ca)
list = subjects == :all ? ca.waiting? : subjects
raise InterfaceError, "No waiting certificate requests to sign" if list.empty?
list.each do |host|
- ca.sign(host)
+ ca.sign(host, options[:allow_dns_alt_names])
end
end
# Set the list of hosts we're operating on. Also supports keywords.
def subjects=(value)
unless value == :all or value == :signed or value.is_a?(Array)
raise ArgumentError, "Subjects must be an array or :all; not #{value}"
end
value = nil if value.is_a?(Array) and value.empty?
@subjects = value
end
end
end
end
end
diff --git a/lib/puppet/ssl/certificate_factory.rb b/lib/puppet/ssl/certificate_factory.rb
index 73290e9cf..cd51ff5d7 100644
--- a/lib/puppet/ssl/certificate_factory.rb
+++ b/lib/puppet/ssl/certificate_factory.rb
@@ -1,145 +1,166 @@
require 'puppet/ssl'
# The tedious class that does all the manipulations to the
# certificate to correctly sign it. Yay.
-class Puppet::SSL::CertificateFactory
+module Puppet::SSL::CertificateFactory
# How we convert from various units to the required seconds.
UNITMAP = {
"y" => 365 * 24 * 60 * 60,
"d" => 24 * 60 * 60,
"h" => 60 * 60,
"s" => 1
}
- attr_reader :name, :cert_type, :csr, :issuer, :serial
+ def self.build(cert_type, csr, issuer, serial)
+ # Work out if we can even build the requested type of certificate.
+ build_extensions = "build_#{cert_type.to_s}_extensions"
+ respond_to?(build_extensions) or
+ raise ArgumentError, "#{cert_type.to_s} is an invalid certificate type!"
- def initialize(cert_type, csr, issuer, serial)
- @cert_type, @csr, @issuer, @serial = cert_type, csr, issuer, serial
+ # set up the certificate, and start building the content.
+ cert = OpenSSL::X509::Certificate.new
- @name = @csr.subject
- end
-
- # Actually generate our certificate.
- def result
- @cert = OpenSSL::X509::Certificate.new
+ cert.version = 2 # X509v3
+ cert.subject = csr.content.subject
+ cert.issuer = issuer.subject
+ cert.public_key = csr.content.public_key
+ cert.serial = serial
- @cert.version = 2 # X509v3
- @cert.subject = @csr.subject
- @cert.issuer = @issuer.subject
- @cert.public_key = @csr.public_key
- @cert.serial = @serial
+ # Make the certificate valid as of yesterday, because so many people's
+ # clocks are out of sync. This gives one more day of validity than people
+ # might expect, but is better than making every person who has a messed up
+ # clock fail, and better than having every cert we generate expire a day
+ # before the user expected it to when they asked for "one year".
+ cert.not_before = Time.now - (60*60*24)
+ cert.not_after = Time.now + ttl
- build_extensions
+ add_extensions_to(cert, csr, issuer, send(build_extensions))
- set_ttl
-
- @cert
+ return cert
end
private
- # This is pretty ugly, but I'm not really sure it's even possible to do
- # it any other way.
- def build_extensions
- @ef = OpenSSL::X509::ExtensionFactory.new
-
- @ef.subject_certificate = @cert
+ def self.add_extensions_to(cert, csr, issuer, extensions)
+ ef = OpenSSL::X509::ExtensionFactory.
+ new(cert, issuer.is_a?(OpenSSL::X509::Request) ? cert : issuer)
- if @issuer.is_a?(OpenSSL::X509::Request) # It's a self-signed cert
- @ef.issuer_certificate = @cert
- else
- @ef.issuer_certificate = @issuer
+ # Extract the requested extensions from the CSR.
+ requested_exts = csr.request_extensions.inject({}) do |hash, re|
+ hash[re["oid"]] = [re["value"], re["critical"]]
+ hash
end
- @subject_alt_name = []
- @key_usage = nil
- @ext_key_usage = nil
- @extensions = []
-
- method = "add_#{@cert_type.to_s}_extensions"
-
- begin
- send(method)
- rescue NoMethodError
- raise ArgumentError, "#{@cert_type} is an invalid certificate type"
+ # Produce our final set of extensions. We deliberately order these to
+ # build the way we want:
+ # 1. "safe" default values, like the comment, that no one cares about.
+ # 2. request extensions, from the CSR
+ # 3. extensions based on the type we are generating
+ # 4. overrides, which we always want to have in their form
+ #
+ # This ordering *is* security-critical, but we want to allow the user
+ # enough rope to shoot themselves in the foot, if they want to ignore our
+ # advice and externally approve a CSR that sets the basicConstraints.
+ #
+ # Swapping the order of 2 and 3 would ensure that you couldn't slip a
+ # certificate through where the CA constraint was true, though, if
+ # something went wrong up there. --daniel 2011-10-11
+ defaults = { "nsComment" => "Puppet Ruby/OpenSSL Internal Certificate" }
+ override = { "subjectKeyIdentifier" => "hash" }
+
+ exts = [defaults, requested_exts, extensions, override].
+ inject({}) {|ret, val| ret.merge(val) }
+
+ cert.extensions = exts.map do |oid, val|
+ val, crit = *val
+ val = val.join(', ') unless val.is_a? String
+
+ # Enforce the X509v3 rules about subjectAltName being critical:
+ # specifically, it SHOULD NOT be critical if we have a subject, which we
+ # always do. --daniel 2011-10-18
+ crit = false if oid == "subjectAltName"
+
+ # val can be either a string, or [string, critical], and this does the
+ # right thing regardless of what we get passed.
+ ef.create_ext(oid, val, crit)
end
-
- @extensions << @ef.create_extension("nsComment", "Puppet Ruby/OpenSSL Generated Certificate")
- @extensions << @ef.create_extension("basicConstraints", @basic_constraint, true)
- @extensions << @ef.create_extension("subjectKeyIdentifier", "hash")
- @extensions << @ef.create_extension("keyUsage", @key_usage.join(",")) if @key_usage
- @extensions << @ef.create_extension("extendedKeyUsage", @ext_key_usage.join(",")) if @ext_key_usage
- @extensions << @ef.create_extension("subjectAltName", @subject_alt_name.join(",")) if ! @subject_alt_name.empty?
-
- @cert.extensions = @extensions
-
- # for some reason this _must_ be the last extension added
- @extensions << @ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if @cert_type == :ca
end
# TTL for new certificates in seconds. If config param :ca_ttl is set,
# use that, otherwise use :ca_days for backwards compatibility
- def ttl
+ def self.ttl
ttl = Puppet.settings[:ca_ttl]
return ttl unless ttl.is_a?(String)
raise ArgumentError, "Invalid ca_ttl #{ttl}" unless ttl =~ /^(\d+)(y|d|h|s)$/
$1.to_i * UNITMAP[$2]
end
- def set_ttl
- # Make the certificate valid as of yesterday, because
- # so many people's clocks are out of sync.
- from = Time.now - (60*60*24)
- @cert.not_before = from
- @cert.not_after = from + ttl
- end
-
# Woot! We're a CA.
- def add_ca_extensions
- @basic_constraint = "CA:TRUE"
- @key_usage = %w{cRLSign keyCertSign}
+ def self.build_ca_extensions
+ {
+ # This was accidentally omitted in the previous version of this code: an
+ # effort was made to add it last, but that actually managed to avoid
+ # adding it to the certificate at all.
+ #
+ # We have some sort of bug, which means that when we add it we get a
+ # complaint that the issuer keyid can't be fetched, which breaks all
+ # sorts of things in our test suite and, e.g., bootstrapping the CA.
+ #
+ # http://tools.ietf.org/html/rfc5280#section-4.2.1.1 says that, to be a
+ # conforming CA we MAY omit the field if we are self-signed, which I
+ # think gives us a pass in the specific case.
+ #
+ # It also notes that we MAY derive the ID from the subject and serial
+ # number of the issuer, or from the key ID, and we definitely have the
+ # former data, should we want to restore this...
+ #
+ # Anyway, preserving this bug means we don't risk breaking anything in
+ # the field, even though it would be nice to have. --daniel 2011-10-11
+ #
+ # "authorityKeyIdentifier" => "keyid:always,issuer:always",
+ "keyUsage" => [%w{cRLSign keyCertSign}, true],
+ "basicConstraints" => ["CA:TRUE", true],
+ }
end
# We're a terminal CA, probably not self-signed.
- def add_terminalsubca_extensions
- @basic_constraint = "CA:TRUE,pathlen:0"
- @key_usage = %w{cRLSign keyCertSign}
+ def self.build_terminalsubca_extensions
+ {
+ "keyUsage" => [%w{cRLSign keyCertSign}, true],
+ "basicConstraints" => ["CA:TRUE,pathlen:0", true],
+ }
end
# We're a normal server.
- def add_server_extensions
- @basic_constraint = "CA:FALSE"
- dnsnames = Puppet[:certdnsnames]
- name = @name.to_s.sub(%r{/CN=},'')
- if dnsnames != ""
- dnsnames.split(':').each { |d| @subject_alt_name << 'DNS:' + d }
- @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
- @subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
- @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- @subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
- end
- @key_usage = %w{digitalSignature keyEncipherment}
- @ext_key_usage = %w{serverAuth clientAuth emailProtection}
+ def self.build_server_extensions
+ {
+ "keyUsage" => [%w{digitalSignature keyEncipherment}, true],
+ "extendedKeyUsage" => [%w{serverAuth clientAuth}, true],
+ "basicConstraints" => ["CA:FALSE", true],
+ }
end
# Um, no idea.
- def add_ocsp_extensions
- @basic_constraint = "CA:FALSE"
- @key_usage = %w{nonRepudiation digitalSignature}
- @ext_key_usage = %w{serverAuth OCSPSigning}
+ def self.build_ocsp_extensions
+ {
+ "keyUsage" => [%w{nonRepudiation digitalSignature}, true],
+ "extendedKeyUsage" => [%w{serverAuth OCSPSigning}, true],
+ "basicConstraints" => ["CA:FALSE", true],
+ }
end
# Normal client.
- def add_client_extensions
- @basic_constraint = "CA:FALSE"
- @key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
- @ext_key_usage = %w{clientAuth emailProtection}
-
- @extensions << @ef.create_extension("nsCertType", "client,email")
+ def self.build_client_extensions
+ {
+ "keyUsage" => [%w{nonRepudiation digitalSignature keyEncipherment}, true],
+ # We don't seem to use this, but that seems much more reasonable here...
+ "extendedKeyUsage" => [%w{clientAuth emailProtection}, true],
+ "basicConstraints" => ["CA:FALSE", true],
+ "nsCertType" => "client,email",
+ }
end
end
diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb
index 8c83339a1..b5ba86113 100644
--- a/lib/puppet/ssl/certificate_request.rb
+++ b/lib/puppet/ssl/certificate_request.rb
@@ -1,62 +1,219 @@
require 'puppet/ssl/base'
# Manage certificate requests.
class Puppet::SSL::CertificateRequest < Puppet::SSL::Base
wraps OpenSSL::X509::Request
extend Puppet::Indirector
# If auto-signing is on, sign any certificate requests as they are saved.
module AutoSigner
def save(instance, key = nil)
super
# Try to autosign the CSR.
if ca = Puppet::SSL::CertificateAuthority.instance
ca.autosign
end
end
end
indirects :certificate_request, :terminus_class => :file, :extend => AutoSigner
# Convert a string into an instance.
def self.from_s(string)
instance = wrapped_class.new(string)
name = instance.subject.to_s.sub(/\/CN=/i, '').downcase
result = new(name)
result.content = instance
result
end
# Because of how the format handler class is included, this
# can't be in the base class.
def self.supported_formats
[:s]
end
+ def extension_factory
+ @ef ||= OpenSSL::X509::ExtensionFactory.new
+ end
+
# How to create a certificate request with our system defaults.
- def generate(key)
+ def generate(key, options = {})
Puppet.info "Creating a new SSL certificate request for #{name}"
# Support either an actual SSL key, or a Puppet key.
key = key.content if key.is_a?(Puppet::SSL::Key)
# If we're a CSR for the CA, then use the real ca_name, rather than the
# fake 'ca' name. This is mostly for backward compatibility with 0.24.x,
# but it's also just a good idea.
common_name = name == Puppet::SSL::CA_NAME ? Puppet.settings[:ca_name] : name
csr = OpenSSL::X509::Request.new
csr.version = 0
csr.subject = OpenSSL::X509::Name.new([["CN", common_name]])
csr.public_key = key.public_key
+
+ if options[:dns_alt_names] then
+ names = options[:dns_alt_names].split(/\s*,\s*/).map(&:strip) + [name]
+ names = names.sort.uniq.map {|name| "DNS:#{name}" }.join(", ")
+ names = extension_factory.create_extension("subjectAltName", names, false)
+
+ extReq = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence([names])])
+
+ # We only support the standard request extensions. If you really need
+ # msExtReq support, let us know and we can restore them. --daniel 2011-10-10
+ csr.add_attribute(OpenSSL::X509::Attribute.new("extReq", extReq))
+ end
+
csr.sign(key, OpenSSL::Digest::MD5.new)
raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for #{name} on the server" unless csr.verify(key.public_key)
@content = csr
Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}"
@content
end
+
+ # Return the set of extensions requested on this CSR, in a form designed to
+ # be useful to Ruby: a hash. Which, not coincidentally, you can pass
+ # successfully to the OpenSSL constructor later, if you want.
+ def request_extensions
+ raise Puppet::Error, "CSR needs content to extract fields" unless @content
+
+ # Prefer the standard extReq, but accept the Microsoft specific version as
+ # a fallback, if the standard version isn't found.
+ ext = @content.attributes.find {|x| x.oid == "extReq" } or
+ @content.attributes.find {|x| x.oid == "msExtReq" }
+ return [] unless ext
+
+ # Assert the structure and extract the names into an array of arrays.
+ unless ext.value.is_a? OpenSSL::ASN1::Set
+ raise Puppet::Error, "In #{ext.oid}, expected Set but found #{ext.value.class}"
+ end
+
+ unless ext.value.value.is_a? Array
+ raise Puppet::Error, "In #{ext.oid}, expected Set[Array] but found #{ext.value.value.class}"
+ end
+
+ unless ext.value.value.length == 1
+ raise Puppet::Error, "In #{ext.oid}, expected Set[Array[...]], but found #{ext.value.value.length} items in the array"
+ end
+
+ san = ext.value.value.first
+ unless san.is_a? OpenSSL::ASN1::Sequence
+ raise Puppet::Error, "In #{ext.oid}, expected Set[Array[Sequence[...]]], but found #{san.class}"
+ end
+ san = san.value
+
+ # OK, now san should be the array of items, validate that...
+ index = -1
+ san.map do |name|
+ index += 1
+
+ unless name.is_a? OpenSSL::ASN1::Sequence
+ raise Puppet::Error, "In #{ext.oid}, expected request extension record #{index} to be a Sequence, but found #{name.class}"
+ end
+ name = name.value
+
+ # OK, turn that into an extension, to unpack the content. Lovely that
+ # we have to swap the order of arguments to the underlying method, or
+ # perhaps that the ASN.1 representation chose to pack them in a
+ # strange order where the optional component comes *earlier* than the
+ # fixed component in the sequence.
+ case name.length
+ when 2
+ ev = OpenSSL::X509::Extension.new(name[0].value, name[1].value)
+ { "oid" => ev.oid, "value" => ev.value }
+
+ when 3
+ ev = OpenSSL::X509::Extension.new(name[0].value, name[2].value, name[1].value)
+ { "oid" => ev.oid, "value" => ev.value, "critical" => ev.critical? }
+
+ else
+ raise Puppet::Error, "In #{ext.oid}, expected extension record #{index} to have two or three items, but found #{name.length}"
+ end
+ end.flatten
+ end
+
+ def subject_alt_names
+ @subject_alt_names ||= request_extensions.
+ select {|x| x["oid"] = "subjectAltName" }.
+ map {|x| x["value"].split(/\s*,\s*/) }.
+ flatten.
+ sort.
+ uniq
+ end
+
+ # Return the set of extensions requested on this CSR, in a form designed to
+ # be useful to Ruby: a hash. Which, not coincidentally, you can pass
+ # successfully to the OpenSSL constructor later, if you want.
+ def request_extensions
+ raise Puppet::Error, "CSR needs content to extract fields" unless @content
+
+ # Prefer the standard extReq, but accept the Microsoft specific version as
+ # a fallback, if the standard version isn't found.
+ ext = @content.attributes.find {|x| x.oid == "extReq" } or
+ @content.attributes.find {|x| x.oid == "msExtReq" }
+ return [] unless ext
+
+ # Assert the structure and extract the names into an array of arrays.
+ unless ext.value.is_a? OpenSSL::ASN1::Set
+ raise Puppet::Error, "In #{ext.oid}, expected Set but found #{ext.value.class}"
+ end
+
+ unless ext.value.value.is_a? Array
+ raise Puppet::Error, "In #{ext.oid}, expected Set[Array] but found #{ext.value.value.class}"
+ end
+
+ unless ext.value.value.length == 1
+ raise Puppet::Error, "In #{ext.oid}, expected Set[Array[...]], but found #{ext.value.value.length} items in the array"
+ end
+
+ san = ext.value.value.first
+ unless san.is_a? OpenSSL::ASN1::Sequence
+ raise Puppet::Error, "In #{ext.oid}, expected Set[Array[Sequence[...]]], but found #{san.class}"
+ end
+ san = san.value
+
+ # OK, now san should be the array of items, validate that...
+ index = -1
+ san.map do |name|
+ index += 1
+
+ unless name.is_a? OpenSSL::ASN1::Sequence
+ raise Puppet::Error, "In #{ext.oid}, expected request extension record #{index} to be a Sequence, but found #{name.class}"
+ end
+ name = name.value
+
+ # OK, turn that into an extension, to unpack the content. Lovely that
+ # we have to swap the order of arguments to the underlying method, or
+ # perhaps that the ASN.1 representation chose to pack them in a
+ # strange order where the optional component comes *earlier* than the
+ # fixed component in the sequence.
+ case name.length
+ when 2
+ ev = OpenSSL::X509::Extension.new(name[0].value, name[1].value)
+ { "oid" => ev.oid, "value" => ev.value }
+
+ when 3
+ ev = OpenSSL::X509::Extension.new(name[0].value, name[2].value, name[1].value)
+ { "oid" => ev.oid, "value" => ev.value, "critical" => ev.critical? }
+
+ else
+ raise Puppet::Error, "In #{ext.oid}, expected extension record #{index} to have two or three items, but found #{name.length}"
+ end
+ end.flatten
+ end
+
+ def subject_alt_names
+ @subject_alt_names ||= request_extensions.
+ select {|x| x["oid"] = "subjectAltName" }.
+ map {|x| x["value"].split(/\s*,\s*/) }.
+ flatten.
+ sort.
+ uniq
+ end
end
diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb
index 28a0819d7..468779870 100644
--- a/lib/puppet/ssl/host.rb
+++ b/lib/puppet/ssl/host.rb
@@ -1,312 +1,329 @@
require 'puppet/indirector'
require 'puppet/ssl'
require 'puppet/ssl/key'
require 'puppet/ssl/certificate'
require 'puppet/ssl/certificate_request'
require 'puppet/ssl/certificate_revocation_list'
# The class that manages all aspects of our SSL certificates --
# private keys, public keys, requests, etc.
class Puppet::SSL::Host
# Yay, ruby's strange constant lookups.
Key = Puppet::SSL::Key
CA_NAME = Puppet::SSL::CA_NAME
Certificate = Puppet::SSL::Certificate
CertificateRequest = Puppet::SSL::CertificateRequest
CertificateRevocationList = Puppet::SSL::CertificateRevocationList
extend Puppet::Indirector
indirects :certificate_status, :terminus_class => :file
attr_reader :name
attr_accessor :ca
attr_writer :key, :certificate, :certificate_request
# This accessor is used in instances for indirector requests to hold desired state
attr_accessor :desired_state
def self.localhost
return @localhost if @localhost
@localhost = new
@localhost.generate unless @localhost.certificate
@localhost.key
@localhost
end
def self.reset
@localhost = nil
end
# This is the constant that people will use to mark that a given host is
# a certificate authority.
def self.ca_name
CA_NAME
end
class << self
attr_reader :ca_location
end
# Configure how our various classes interact with their various terminuses.
def self.configure_indirection(terminus, cache = nil)
Certificate.indirection.terminus_class = terminus
CertificateRequest.indirection.terminus_class = terminus
CertificateRevocationList.indirection.terminus_class = terminus
host_map = {:ca => :file, :file => nil, :rest => :rest}
if term = host_map[terminus]
self.indirection.terminus_class = term
else
self.indirection.reset_terminus_class
end
if cache
# This is weird; we don't actually cache our keys, we
# use what would otherwise be the cache as our normal
# terminus.
Key.indirection.terminus_class = cache
else
Key.indirection.terminus_class = terminus
end
if cache
Certificate.indirection.cache_class = cache
CertificateRequest.indirection.cache_class = cache
CertificateRevocationList.indirection.cache_class = cache
else
# Make sure we have no cache configured. puppet master
# switches the configurations around a bit, so it's important
# that we specify the configs for absolutely everything, every
# time.
Certificate.indirection.cache_class = nil
CertificateRequest.indirection.cache_class = nil
CertificateRevocationList.indirection.cache_class = nil
end
end
CA_MODES = {
# Our ca is local, so we use it as the ultimate source of information
# And we cache files locally.
:local => [:ca, :file],
# We're a remote CA client.
:remote => [:rest, :file],
# We are the CA, so we don't have read/write access to the normal certificates.
:only => [:ca],
# We have no CA, so we just look in the local file store.
:none => [:file]
}
# Specify how we expect to interact with our certificate authority.
def self.ca_location=(mode)
modes = CA_MODES.collect { |m, vals| m.to_s }.join(", ")
raise ArgumentError, "CA Mode can only be one of: #{modes}" unless CA_MODES.include?(mode)
@ca_location = mode
configure_indirection(*CA_MODES[@ca_location])
end
# Puppet::SSL::Host is actually indirected now so the original implementation
# has been moved into the certificate_status indirector. This method is in-use
# in `puppet cert -c <certname>`.
def self.destroy(name)
indirection.destroy(name)
end
def self.from_pson(pson)
instance = new(pson["name"])
if pson["desired_state"]
instance.desired_state = pson["desired_state"]
end
instance
end
# Puppet::SSL::Host is actually indirected now so the original implementation
# has been moved into the certificate_status indirector. This method does not
# appear to be in use in `puppet cert -l`.
def self.search(options = {})
indirection.search("*", options)
end
# Is this a ca host, meaning that all of its files go in the CA location?
def ca?
ca
end
def key
@key ||= Key.indirection.find(name)
end
# This is the private key; we can create it from scratch
# with no inputs.
def generate_key
@key = Key.new(name)
@key.generate
begin
Key.indirection.save(@key)
rescue
@key = nil
raise
end
true
end
def certificate_request
@certificate_request ||= CertificateRequest.indirection.find(name)
end
+ def this_csr_is_for_the_current_host
+ name == Puppet[:certname].downcase
+ end
+
+ def this_csr_is_for_the_current_host
+ name == Puppet[:certname].downcase
+ end
+
# Our certificate request requires the key but that's all.
- def generate_certificate_request
+ def generate_certificate_request(options = {})
generate_key unless key
+
+ # If this is for the current machine...
+ if this_csr_is_for_the_current_host
+ # ...add our configured dns_alt_names
+ if Puppet[:dns_alt_names] and Puppet[:dns_alt_names] != ''
+ options[:dns_alt_names] ||= Puppet[:dns_alt_names]
+ end
+ end
+
@certificate_request = CertificateRequest.new(name)
- @certificate_request.generate(key.content)
+ @certificate_request.generate(key.content, options)
begin
CertificateRequest.indirection.save(@certificate_request)
rescue
@certificate_request = nil
raise
end
true
end
def certificate
unless @certificate
generate_key unless key
# get the CA cert first, since it's required for the normal cert
# to be of any use.
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
end
@certificate
end
def certificate_matches_key?
return false unless key
return false unless certificate
certificate.content.check_private_key(key.content)
end
# Generate all necessary parts of our ssl host.
def generate
generate_key unless key
generate_certificate_request unless certificate_request
# If we can get a CA instance, then we're a valid CA, and we
# should use it to sign our request; else, just try to read
# the cert.
if ! certificate and ca = Puppet::SSL::CertificateAuthority.instance
- ca.sign(self.name)
+ ca.sign(self.name, true)
end
end
def initialize(name = nil)
@name = (name || Puppet[:certname]).downcase
@key = @certificate = @certificate_request = nil
@ca = (name == self.class.ca_name)
end
# Extract the public key from the private key.
def public_key
key.content.public_key
end
# Create/return a store that uses our SSL info to validate
# connections.
def ssl_store(purpose = OpenSSL::X509::PURPOSE_ANY)
unless @ssl_store
@ssl_store = OpenSSL::X509::Store.new
@ssl_store.purpose = purpose
# Use the file path here, because we don't want to cause
# a lookup in the middle of setting our ssl connection.
@ssl_store.add_file(Puppet[:localcacert])
# If there's a CRL, add it to our store.
if crl = Puppet::SSL::CertificateRevocationList.indirection.find(CA_NAME)
@ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
@ssl_store.add_crl(crl.content)
end
return @ssl_store
end
@ssl_store
end
def to_pson(*args)
my_cert = Puppet::SSL::Certificate.indirection.find(name)
pson_hash = { :name => name }
my_state = state
pson_hash[:state] = my_state
pson_hash[:desired_state] = desired_state if desired_state
if my_state == 'requested'
pson_hash[:fingerprint] = certificate_request.fingerprint
else
pson_hash[:fingerprint] = my_cert.fingerprint
end
pson_hash.to_pson(*args)
end
# Attempt to retrieve a cert, if we don't already have one.
def wait_for_cert(time)
begin
return if certificate
generate
return if certificate
rescue SystemExit,NoMemoryError
raise
rescue Exception => detail
puts detail.backtrace if Puppet[:trace]
Puppet.err "Could not request certificate: #{detail}"
if time < 1
puts "Exiting; failed to retrieve certificate and waitforcert is disabled"
exit(1)
else
sleep(time)
end
retry
end
if time < 1
puts "Exiting; no certificate found and waitforcert is disabled"
exit(1)
end
while true
sleep time
begin
break if certificate
Puppet.notice "Did not receive certificate"
rescue StandardError => detail
puts detail.backtrace if Puppet[:trace]
Puppet.err "Could not request certificate: #{detail}"
end
end
end
def state
my_cert = Puppet::SSL::Certificate.indirection.find(name)
if certificate_request
return 'requested'
end
begin
Puppet::SSL::CertificateAuthority.new.verify(my_cert)
return 'signed'
rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError
return 'revoked'
end
end
end
require 'puppet/ssl/certificate_authority'
diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb
deleted file mode 100755
index 4e941244e..000000000
--- a/lib/puppet/sslcertificates.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-# The library for manipulating SSL certs.
-
-require 'puppet'
-
-raise Puppet::Error, "You must have the Ruby openssl library installed" unless Puppet.features.openssl?
-
-module Puppet::SSLCertificates
- #def self.mkcert(type, name, dnsnames, ttl, issuercert, issuername, serial, publickey)
- def self.mkcert(hash)
- [:type, :name, :ttl, :issuer, :serial, :publickey].each { |param|
- raise ArgumentError, "mkcert called without #{param}" unless hash.include?(param)
- }
-
- cert = OpenSSL::X509::Certificate.new
- # Make the certificate valid as of yesterday, because
- # so many people's clocks are out of sync.
- from = Time.now - (60*60*24)
-
- cert.subject = hash[:name]
- if hash[:issuer]
- cert.issuer = hash[:issuer].subject
- else
- # we're a self-signed cert
- cert.issuer = hash[:name]
- end
- cert.not_before = from
- cert.not_after = from + hash[:ttl]
- cert.version = 2 # X509v3
-
- cert.public_key = hash[:publickey]
- cert.serial = hash[:serial]
-
- basic_constraint = nil
- key_usage = nil
- ext_key_usage = nil
- subject_alt_name = []
-
- ef = OpenSSL::X509::ExtensionFactory.new
-
- ef.subject_certificate = cert
-
- if hash[:issuer]
- ef.issuer_certificate = hash[:issuer]
- else
- ef.issuer_certificate = cert
- end
-
- ex = []
- case hash[:type]
- when :ca
- basic_constraint = "CA:TRUE"
- key_usage = %w{cRLSign keyCertSign}
- when :terminalsubca
- basic_constraint = "CA:TRUE,pathlen:0"
- key_usage = %w{cRLSign keyCertSign}
- when :server
- basic_constraint = "CA:FALSE"
- dnsnames = Puppet[:certdnsnames]
- name = hash[:name].to_s.sub(%r{/CN=},'')
- if dnsnames != ""
- dnsnames.split(':').each { |d| subject_alt_name << 'DNS:' + d }
- subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
- subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
- subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
- end
- key_usage = %w{digitalSignature keyEncipherment}
- ext_key_usage = %w{serverAuth clientAuth emailProtection}
- when :ocsp
- basic_constraint = "CA:FALSE"
- key_usage = %w{nonRepudiation digitalSignature}
- ext_key_usage = %w{serverAuth OCSPSigning}
- when :client
- basic_constraint = "CA:FALSE"
- key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
- ext_key_usage = %w{clientAuth emailProtection}
- ex << ef.create_extension("nsCertType", "client,email")
- else
- raise Puppet::Error, "unknown cert type '#{hash[:type]}'"
- end
-
-
- ex << ef.create_extension(
- "nsComment",
-
- "Puppet Ruby/OpenSSL Generated Certificate")
- ex << ef.create_extension("basicConstraints", basic_constraint, true)
- ex << ef.create_extension("subjectKeyIdentifier", "hash")
-
- ex << ef.create_extension("keyUsage", key_usage.join(",")) if key_usage
- ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) if ext_key_usage
- ex << ef.create_extension("subjectAltName", subject_alt_name.join(",")) if ! subject_alt_name.empty?
-
- #if @ca_config[:cdp_location] then
- # ex << ef.create_extension("crlDistributionPoints",
- # @ca_config[:cdp_location])
- #end
-
- #if @ca_config[:ocsp_location] then
- # ex << ef.create_extension("authorityInfoAccess",
- # "OCSP;" << @ca_config[:ocsp_location])
- #end
- cert.extensions = ex
-
- # for some reason this _must_ be the last extension added
- ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if hash[:type] == :ca
-
- cert
- end
-
- def self.mkhash(dir, cert, certfile)
- # Make sure the hash is zero-padded to 8 chars
- hash = "%08x" % cert.issuer.hash
- hashpath = nil
- 10.times { |i|
- path = File.join(dir, "#{hash}.#{i}")
- if FileTest.exists?(path)
- if FileTest.symlink?(path)
- dest = File.readlink(path)
- if dest == certfile
- # the correct link already exists
- hashpath = path
- break
- else
- next
- end
- else
- next
- end
- end
-
- File.symlink(certfile, path)
-
- hashpath = path
- break
- }
-
-
- hashpath
- end
- require 'puppet/sslcertificates/certificate'
- require 'puppet/sslcertificates/inventory'
- require 'puppet/sslcertificates/ca'
-end
-
diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb
deleted file mode 100644
index f3321bd29..000000000
--- a/lib/puppet/sslcertificates/ca.rb
+++ /dev/null
@@ -1,375 +0,0 @@
-require 'sync'
-
-class Puppet::SSLCertificates::CA
- include Puppet::Util::Warnings
-
- Certificate = Puppet::SSLCertificates::Certificate
- attr_accessor :keyfile, :file, :config, :dir, :cert, :crl
-
- def certfile
- @config[:cacert]
- end
-
- # Remove all traces of a given host. This is kind of hackish, but, eh.
- def clean(host)
- host = host.downcase
- [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name|
- dir = Puppet[name]
-
- file = File.join(dir, host + ".pem")
-
- if FileTest.exists?(file)
- begin
- if Puppet[:name] == "cert"
- puts "Removing #{file}"
- else
- Puppet.info "Removing #{file}"
- end
- File.unlink(file)
- rescue => detail
- raise Puppet::Error, "Could not delete #{file}: #{detail}"
- end
- end
-
- end
- end
-
- def host2csrfile(hostname)
- File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join("."))
- end
-
- # this stores signed certs in a directory unrelated to
- # normal client certs
- def host2certfile(hostname)
- File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join("."))
- end
-
- # Turn our hostname into a Name object
- def thing2name(thing)
- thing.subject.to_a.find { |ary|
- ary[0] == "CN"
- }[1]
- end
-
- def initialize(hash = {})
- Puppet.settings.use(:main, :ca, :ssl)
- self.setconfig(hash)
-
- if Puppet[:capass]
- if FileTest.exists?(Puppet[:capass])
- #puts "Reading #{Puppet[:capass]}"
- #system "ls -al #{Puppet[:capass]}"
- #File.read Puppet[:capass]
- @config[:password] = self.getpass
- else
- # Don't create a password if the cert already exists
- @config[:password] = self.genpass unless FileTest.exists?(@config[:cacert])
- end
- end
-
- self.getcert
- init_crl
- unless FileTest.exists?(@config[:serial])
- Puppet.settings.write(:serial) do |f|
- f << "%04X" % 1
- end
- end
- end
-
- # Generate a new password for the CA.
- def genpass
- pass = ""
- 20.times { pass += (rand(74) + 48).chr }
-
- begin
- Puppet.settings.write(:capass) { |f| f.print pass }
- rescue Errno::EACCES => detail
- raise Puppet::Error, detail.to_s
- end
- pass
- end
-
- # Get the CA password.
- def getpass
- if @config[:capass] and File.readable?(@config[:capass])
- return File.read(@config[:capass])
- else
- raise Puppet::Error, "Could not decrypt CA key with password: #{detail}"
- end
- end
-
- # Get the CA cert.
- def getcert
- if FileTest.exists?(@config[:cacert])
- @cert = OpenSSL::X509::Certificate.new(
- File.read(@config[:cacert])
- )
- else
- self.mkrootcert
- end
- end
-
- # Retrieve a client's CSR.
- def getclientcsr(host)
- csrfile = host2csrfile(host)
- return nil unless File.exists?(csrfile)
-
- OpenSSL::X509::Request.new(File.read(csrfile))
- end
-
- # Retrieve a client's certificate.
- def getclientcert(host)
- certfile = host2certfile(host)
- return [nil, nil] unless File.exists?(certfile)
-
- [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
- end
-
- # List certificates waiting to be signed. This returns a list of hostnames, not actual
- # files -- the names can be converted to full paths with host2csrfile.
- def list(dummy_argument=:work_arround_for_ruby_GC_bug)
- return Dir.entries(Puppet[:csrdir]).find_all { |file|
- file =~ /\.pem$/
- }.collect { |file|
- file.sub(/\.pem$/, '')
- }
- end
-
- # List signed certificates. This returns a list of hostnames, not actual
- # files -- the names can be converted to full paths with host2csrfile.
- def list_signed(dummy_argument=:work_arround_for_ruby_GC_bug)
- return Dir.entries(Puppet[:signeddir]).find_all { |file|
- file =~ /\.pem$/
- }.collect { |file|
- file.sub(/\.pem$/, '')
- }
- end
-
- # Create the root certificate.
- def mkrootcert
- # Make the root cert's name "Puppet CA: " plus the FQDN of the host running the CA.
- name = "Puppet CA: #{Facter["hostname"].value}"
- if domain = Facter["domain"].value
- name += ".#{domain}"
- end
-
- cert = Certificate.new(
- :name => name,
- :cert => @config[:cacert],
- :encrypt => @config[:capass],
- :key => @config[:cakey],
- :selfsign => true,
- :ttl => ttl,
- :type => :ca
- )
-
- # This creates the cakey file
- Puppet::Util::SUIDManager.asuser(Puppet[:user], Puppet[:group]) do
- @cert = cert.mkselfsigned
- end
- Puppet.settings.write(:cacert) do |f|
- f.puts @cert.to_pem
- end
- Puppet.settings.write(:capub) do |f|
- f.puts @cert.public_key
- end
- cert
- end
-
- def removeclientcsr(host)
- csrfile = host2csrfile(host)
- raise Puppet::Error, "No certificate request for #{host}" unless File.exists?(csrfile)
-
- File.unlink(csrfile)
- end
-
- # Revoke the certificate with serial number SERIAL issued by this
- # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
- def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
- time = Time.now
- revoked = OpenSSL::X509::Revoked.new
- revoked.serial = serial
- revoked.time = time
- enum = OpenSSL::ASN1::Enumerated(reason)
- ext = OpenSSL::X509::Extension.new("CRLReason", enum)
- revoked.add_extension(ext)
- @crl.add_revoked(revoked)
- store_crl
- end
-
- # Take the Puppet config and store it locally.
- def setconfig(hash)
- @config = {}
- Puppet.settings.params("ca").each { |param|
- param = param.intern if param.is_a? String
- if hash.include?(param)
- @config[param] = hash[param]
- Puppet[param] = hash[param]
- hash.delete(param)
- else
- @config[param] = Puppet[param]
- end
- }
-
- if hash.include?(:password)
- @config[:password] = hash[:password]
- hash.delete(:password)
- end
-
- raise ArgumentError, "Unknown parameters #{hash.keys.join(",")}" if hash.length > 0
-
- [:cadir, :csrdir, :signeddir].each { |dir|
- raise Puppet::DevError, "#{dir} is undefined" unless @config[dir]
- }
- end
-
- # Sign a given certificate request.
- def sign(csr)
- unless csr.is_a?(OpenSSL::X509::Request)
- raise Puppet::Error,
- "CA#sign only accepts OpenSSL::X509::Request objects, not #{csr.class}"
- end
-
- raise Puppet::Error, "CSR sign verification failed" unless csr.verify(csr.public_key)
-
- serial = nil
- Puppet.settings.readwritelock(:serial) { |f|
- serial = File.read(@config[:serial]).chomp.hex
- # increment the serial
- f << "%04X" % (serial + 1)
- }
-
- newcert = Puppet::SSLCertificates.mkcert(
- :type => :server,
- :name => csr.subject,
- :ttl => ttl,
- :issuer => @cert,
- :serial => serial,
- :publickey => csr.public_key
- )
-
- sign_with_key(newcert)
-
- self.storeclientcert(newcert)
-
- [newcert, @cert]
- end
-
- # Store the client's CSR for later signing. This is called from
- # server/ca.rb, and the CSRs are deleted once the certificate is actually
- # signed.
- def storeclientcsr(csr)
- host = thing2name(csr)
-
- csrfile = host2csrfile(host)
- raise Puppet::Error, "Certificate request for #{host} already exists" if File.exists?(csrfile)
-
- Puppet.settings.writesub(:csrdir, csrfile) do |f|
- f.print csr.to_pem
- end
- end
-
- # Store the certificate that we generate.
- def storeclientcert(cert)
- host = thing2name(cert)
-
- certfile = host2certfile(host)
- Puppet.notice "Overwriting signed certificate #{certfile} for #{host}" if File.exists?(certfile)
-
- Puppet::SSLCertificates::Inventory::add(cert)
- Puppet.settings.writesub(:signeddir, certfile) do |f|
- f.print cert.to_pem
- end
- end
-
- # TTL for new certificates in seconds. If config param :ca_ttl is set,
- # use that, otherwise use :ca_days for backwards compatibility
- def ttl
- days = @config[:ca_days]
- if days && days.size > 0
- warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead."
- return @config[:ca_days] * 24 * 60 * 60
- else
- ttl = @config[:ca_ttl]
- if ttl.is_a?(String)
- unless ttl =~ /^(\d+)(y|d|h|s)$/
- raise ArgumentError, "Invalid ca_ttl #{ttl}"
- end
- case $2
- when 'y'
- unit = 365 * 24 * 60 * 60
- when 'd'
- unit = 24 * 60 * 60
- when 'h'
- unit = 60 * 60
- when 's'
- unit = 1
- else
- raise ArgumentError, "Invalid unit for ca_ttl #{ttl}"
- end
- return $1.to_i * unit
- else
- return ttl
- end
- end
- end
-
- private
- def init_crl
- if FileTest.exists?(@config[:cacrl])
- @crl = OpenSSL::X509::CRL.new(
- File.read(@config[:cacrl])
- )
- else
- # Create new CRL
- @crl = OpenSSL::X509::CRL.new
- @crl.issuer = @cert.subject
- @crl.version = 1
- store_crl
- @crl
- end
- end
-
- def store_crl
- # Increment the crlNumber
- e = @crl.extensions.find { |e| e.oid == 'crlNumber' }
- ext = @crl.extensions.reject { |e| e.oid == 'crlNumber' }
- crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
- ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
- @crl.extensions = ext
-
- # Set last/next update
- now = Time.now
- @crl.last_update = now
- # Keep CRL valid for 5 years
- @crl.next_update = now + 5 * 365*24*60*60
-
- sign_with_key(@crl)
- Puppet.settings.write(:cacrl) do |f|
- f.puts @crl.to_pem
- end
- end
-
- def sign_with_key(signable, digest = OpenSSL::Digest::SHA1.new)
- cakey = nil
- if @config[:password]
- begin
- cakey = OpenSSL::PKey::RSA.new(
- File.read(@config[:cakey]), @config[:password]
- )
- rescue
- raise Puppet::Error,
- "Decrypt of CA private key with password stored in @config[:capass] not possible"
- end
- else
- cakey = OpenSSL::PKey::RSA.new(
- File.read(@config[:cakey])
- )
- end
-
- raise Puppet::Error, "CA Certificate is invalid" unless @cert.check_private_key(cakey)
-
- signable.sign(cakey, digest)
- end
-end
-
diff --git a/lib/puppet/sslcertificates/certificate.rb b/lib/puppet/sslcertificates/certificate.rb
deleted file mode 100644
index 2d30bb09f..000000000
--- a/lib/puppet/sslcertificates/certificate.rb
+++ /dev/null
@@ -1,255 +0,0 @@
-class Puppet::SSLCertificates::Certificate
- SSLCertificates = Puppet::SSLCertificates
-
- attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type
- attr_accessor :key, :cert, :csr, :cacert
-
- @@params2names = {
- :name => "CN",
- :state => "ST",
- :country => "C",
- :email => "emailAddress",
- :org => "O",
- :city => "L",
- :ou => "OU"
- }
-
- def certname
- OpenSSL::X509::Name.new self.subject
- end
-
- def delete
- [@certfile,@keyfile].each { |file|
- File.unlink(file) if FileTest.exists?(file)
- }
-
- if @hash
- File.unlink(@hash) if FileTest.symlink?(@hash)
- end
- end
-
- def exists?
- FileTest.exists?(@certfile)
- end
-
- def getkey
- self.mkkey unless FileTest.exists?(@keyfile)
- if @password
-
- @key = OpenSSL::PKey::RSA.new(
-
- File.read(@keyfile),
-
- @password
- )
- else
- @key = OpenSSL::PKey::RSA.new(
- File.read(@keyfile)
- )
- end
- end
-
- def initialize(hash)
- raise Puppet::Error, "You must specify the common name for the certificate" unless hash.include?(:name)
- @name = hash[:name]
-
- # init a few variables
- @cert = @key = @csr = nil
-
- if hash.include?(:cert)
- @certfile = hash[:cert]
- @dir = File.dirname(@certfile)
- else
- @dir = hash[:dir] || Puppet[:certdir]
- @certfile = File.join(@dir, @name)
- end
-
- @cacertfile ||= File.join(Puppet[:certdir], "ca.pem")
-
- Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
-
- unless @certfile =~ /\.pem$/
- @certfile += ".pem"
- end
- @keyfile = hash[:key] || File.join(
- Puppet[:privatekeydir], [@name,"pem"].join(".")
- )
- Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
-
- [@keyfile].each { |file|
- dir = File.dirname(file)
-
- Puppet.recmkdir(dir) unless FileTest.directory?(dir)
- }
-
- @ttl = hash[:ttl] || 365 * 24 * 60 * 60
- @selfsign = hash[:selfsign] || false
- @encrypt = hash[:encrypt] || false
- @replace = hash[:replace] || false
- @issuer = hash[:issuer] || nil
-
- if hash.include?(:type)
- case hash[:type]
- when :ca, :client, :server; @type = hash[:type]
- else
- raise "Invalid Cert type #{hash[:type]}"
- end
- else
- @type = :client
- end
-
- @params = {:name => @name}
- [:state, :country, :email, :org, :ou].each { |param|
- @params[param] = hash[param] if hash.include?(param)
- }
-
- if @encrypt
- if @encrypt =~ /^\//
- File.open(@encrypt) { |f|
- @password = f.read.chomp
- }
- else
- raise Puppet::Error, ":encrypt must be a path to a pass phrase file"
- end
- else
- @password = nil
- end
-
- @selfsign = hash.include?(:selfsign) && hash[:selfsign]
- end
-
- # this only works for servers, not for users
- def mkcsr
- self.getkey unless @key
-
- name = OpenSSL::X509::Name.new self.subject
-
- @csr = OpenSSL::X509::Request.new
- @csr.version = 0
- @csr.subject = name
- @csr.public_key = @key.public_key
- @csr.sign(@key, OpenSSL::Digest::SHA1.new)
-
- #File.open(@csrfile, "w") { |f|
- # f << @csr.to_pem
- #}
-
- raise Puppet::Error, "CSR sign verification failed" unless @csr.verify(@key.public_key)
-
- @csr
- end
-
- def mkkey
- # @key is the file
-
- @key = OpenSSL::PKey::RSA.new(1024)
-# { |p,n|
-# case p
-# when 0; Puppet.info "key info: ." # BN_generate_prime
-# when 1; Puppet.info "key info: +" # BN_generate_prime
-# when 2; Puppet.info "key info: *" # searching good prime,
-# # n = #of try,
-# # but also data from BN_generate_prime
-# when 3; Puppet.info "key info: \n" # found good prime, n==0 - p, n==1 - q,
-# # but also data from BN_generate_prime
-# else; Puppet.info "key info: *" # BN_generate_prime
-# end
-# }
-
- if @password
- # passwdproc = proc { @password }
-
- keytext = @key.export(
-
- OpenSSL::Cipher::DES.new(:EDE3, :CBC),
-
- @password
- )
- File.open(@keyfile, "w", 0400) { |f|
- f << keytext
- }
- else
- File.open(@keyfile, "w", 0400) { |f|
- f << @key.to_pem
- }
- end
-
- #cmd = "#{ossl} genrsa -out #{@key} 1024"
- end
-
- def mkselfsigned
- self.getkey unless @key
-
- raise Puppet::Error, "Cannot replace existing certificate" if @cert
-
- args = {
- :name => self.certname,
- :ttl => @ttl,
- :issuer => nil,
- :serial => 0x0,
- :publickey => @key.public_key
- }
- if @type
- args[:type] = @type
- else
- args[:type] = :server
- end
- @cert = SSLCertificates.mkcert(args)
-
- @cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign
-
- @cert
- end
-
- def subject(string = false)
- subj = @@params2names.collect { |param, name|
- [name, @params[param]] if @params.include?(param)
- }.reject { |ary| ary.nil? }
-
- if string
- return "/" + subj.collect { |ary|
- "%s=%s" % ary
- }.join("/") + "/"
- else
- return subj
- end
- end
-
- # verify that we can track down the cert chain or whatever
- def verify
- "openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem"
- end
-
- def write
- files = {
- @certfile => @cert,
- @keyfile => @key,
- }
- files[@cacertfile] = @cacert if defined?(@cacert)
-
- files.each { |file,thing|
- if thing
- next if FileTest.exists?(file)
-
- text = nil
-
- if thing.is_a?(OpenSSL::PKey::RSA) and @password
-
- text = thing.export(
-
- OpenSSL::Cipher::DES.new(:EDE3, :CBC),
-
- @password
- )
- else
- text = thing.to_pem
- end
-
- File.open(file, "w", 0660) { |f| f.print text }
- end
- }
-
- SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile) if defined?(@cacert)
- end
-end
-
diff --git a/lib/puppet/sslcertificates/inventory.rb b/lib/puppet/sslcertificates/inventory.rb
deleted file mode 100644
index 1075c1377..000000000
--- a/lib/puppet/sslcertificates/inventory.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# A module for keeping track of all the certificates issued by the CA, ever
-# Maintains the file "$cadir/inventory.txt"
-module Puppet::SSLCertificates
- module Inventory
-
- # Add CERT to the inventory of issued certs in '$cadir/inventory.txt'
- # If no inventory exists yet, build an inventory and list all the
- # certificates that have been signed so far
- def self.add(cert)
- inited = false
- inited = true if FileTest.exists?(Puppet[:cert_inventory])
-
- Puppet.settings.write(:cert_inventory, "a") do |f|
- f.puts((inited ? nil : self.init).to_s + format(cert))
- end
- end
-
- private
-
- def self.init
- inv = "# Inventory of signed certificates\n"
- inv += "# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n"
- Dir.glob(File::join(Puppet[:signeddir], "*.pem")) do |f|
- inv += format(OpenSSL::X509::Certificate.new(File::read(f))) + "\n"
- end
- inv
- end
-
- def self.format(cert)
- iso = '%Y-%m-%dT%H:%M:%S%Z'
- return "0x%04x %s %s %s" % [cert.serial,
- cert.not_before.strftime(iso),
- cert.not_after.strftime(iso),
- cert.subject]
- end
- end
-end
-
diff --git a/lib/puppet/sslcertificates/support.rb b/lib/puppet/sslcertificates/support.rb
deleted file mode 100644
index 7d6708124..000000000
--- a/lib/puppet/sslcertificates/support.rb
+++ /dev/null
@@ -1,146 +0,0 @@
-require 'puppet/sslcertificates'
-
-# A module to handle reading of certificates.
-module Puppet::SSLCertificates::Support
- class MissingCertificate < Puppet::Error; end
- class InvalidCertificate < Puppet::Error; end
-
- attr_reader :cacert
-
- # Some metaprogramming to create methods for retrieving and creating keys.
- # This probably isn't fewer lines than defining each separately...
- def self.keytype(name, options, &block)
- var = "@#{name}"
-
- maker = "mk_#{name}"
- reader = "read_#{name}"
-
- unless param = options[:param]
- raise ArgumentError, "You must specify the parameter for the key"
- end
-
- unless klass = options[:class]
- raise ArgumentError, "You must specify the class for the key"
- end
-
- # Define the method that creates it.
- define_method(maker, &block)
-
- # Define the reading method.
- define_method(reader) do
- return nil unless FileTest.exists?(Puppet[param]) or rename_files_with_uppercase(Puppet[param])
-
- begin
- instance_variable_set(var, klass.new(File.read(Puppet[param])))
- rescue => detail
- raise InvalidCertificate, "Could not read #{param}: #{detail}"
- end
- end
-
- # Define the overall method, which just calls the reader and maker
- # as appropriate.
- define_method(name) do
- unless cert = instance_variable_get(var)
- unless cert = send(reader)
- cert = send(maker)
- Puppet.settings.write(param) { |f| f.puts cert.to_pem }
- end
- instance_variable_set(var, cert)
- end
- cert
- end
- end
-
- # The key pair.
- keytype :key, :param => :hostprivkey, :class => OpenSSL::PKey::RSA do
- Puppet.info "Creating a new SSL key at #{Puppet[:hostprivkey]}"
- key = OpenSSL::PKey::RSA.new(Puppet[:keylength])
-
- # Our key meta programming can only handle one file, so we have
- # to separately write out the public key.
- Puppet.settings.write(:hostpubkey) do |f|
- f.print key.public_key.to_pem
- end
- return key
- end
-
- # Our certificate request
- keytype :csr, :param => :hostcsr, :class => OpenSSL::X509::Request do
- Puppet.info "Creating a new certificate request for #{Puppet[:certname]}"
-
- csr = OpenSSL::X509::Request.new
- csr.version = 0
- csr.subject = OpenSSL::X509::Name.new([["CN", Puppet[:certname]]])
- csr.public_key = key.public_key
- csr.sign(key, OpenSSL::Digest::MD5.new)
-
- return csr
- end
-
- keytype :cert, :param => :hostcert, :class => OpenSSL::X509::Certificate do
- raise MissingCertificate, "No host certificate"
- end
-
- keytype :ca_cert, :param => :localcacert, :class => OpenSSL::X509::Certificate do
- raise MissingCertificate, "No CA certificate"
- end
-
- # Request a certificate from the remote system. This does all of the work
- # of creating the cert request, contacting the remote system, and
- # storing the cert locally.
- def requestcert
- begin
- cert, cacert = caclient.getcert(@csr.to_pem)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error.new("Certificate retrieval failed: #{detail}")
- end
-
- if cert.nil? or cert == ""
- return nil
- end
- Puppet.settings.write(:hostcert) do |f| f.print cert end
- Puppet.settings.write(:localcacert) do |f| f.print cacert end
- #File.open(@certfile, "w", 0644) { |f| f.print cert }
- #File.open(@cacertfile, "w", 0644) { |f| f.print cacert }
- begin
- @cert = OpenSSL::X509::Certificate.new(cert)
- @cacert = OpenSSL::X509::Certificate.new(cacert)
- retrieved = true
- rescue => detail
- raise Puppet::Error.new(
- "Invalid certificate: #{detail}"
- )
- end
-
- raise Puppet::DevError, "Received invalid certificate" unless @cert.check_private_key(@key)
- retrieved
- end
-
- # A hack method to deal with files that exist with a different case.
- # Just renames it; doesn't read it in or anything.
- def rename_files_with_uppercase(file)
- dir = File.dirname(file)
- short = File.basename(file)
-
- # If the dir isn't present, we clearly don't have the file.
- #return nil unless FileTest.directory?(dir)
-
- raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short
-
- return false unless File.directory?(dir)
-
- real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other|
- other.downcase == short
- end
-
- return nil unless real_file
-
- full_file = File.join(dir, real_file)
-
- Puppet.notice "Fixing case in #{full_file}; renaming to #{file}"
- File.rename(full_file, file)
-
- true
- end
-end
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 3c0cb1b1c..4f18d8400 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -1,1930 +1,1939 @@
require 'puppet'
require 'puppet/util/log'
require 'puppet/util/metric'
require 'puppet/property'
require 'puppet/parameter'
require 'puppet/util'
require 'puppet/util/autoload'
require 'puppet/metatype/manager'
require 'puppet/util/errors'
require 'puppet/util/log_paths'
require 'puppet/util/logging'
require 'puppet/file_collection/lookup'
require 'puppet/util/tagging'
# see the bottom of the file for the rest of the inclusions
module Puppet
class Type
include Puppet::Util
include Puppet::Util::Errors
include Puppet::Util::LogPaths
include Puppet::Util::Logging
include Puppet::FileCollection::Lookup
include Puppet::Util::Tagging
###############################
# Code related to resource type attributes.
class << self
include Puppet::Util::ClassGen
include Puppet::Util::Warnings
attr_reader :properties
end
def self.states
warnonce "The states method is deprecated; use properties"
properties
end
# All parameters, in the appropriate order. The key_attributes come first, then
# the provider, then the properties, and finally the params and metaparams
# in the order they were specified in the files.
def self.allattrs
key_attributes | (parameters & [:provider]) | properties.collect { |property| property.name } | parameters | metaparams
end
# Retrieve an attribute alias, if there is one.
def self.attr_alias(param)
@attr_aliases[symbolize(param)]
end
# Create an alias to an existing attribute. This will cause the aliased
# attribute to be valid when setting and retrieving values on the instance.
def self.set_attr_alias(hash)
hash.each do |new, old|
@attr_aliases[symbolize(new)] = symbolize(old)
end
end
# Find the class associated with any given attribute.
def self.attrclass(name)
@attrclasses ||= {}
# We cache the value, since this method gets called such a huge number
# of times (as in, hundreds of thousands in a given run).
unless @attrclasses.include?(name)
@attrclasses[name] = case self.attrtype(name)
when :property; @validproperties[name]
when :meta; @@metaparamhash[name]
when :param; @paramhash[name]
end
end
@attrclasses[name]
end
# What type of parameter are we dealing with? Cache the results, because
# this method gets called so many times.
def self.attrtype(attr)
@attrtypes ||= {}
unless @attrtypes.include?(attr)
@attrtypes[attr] = case
when @validproperties.include?(attr); :property
when @paramhash.include?(attr); :param
when @@metaparamhash.include?(attr); :meta
end
end
@attrtypes[attr]
end
def self.eachmetaparam
@@metaparams.each { |p| yield p.name }
end
# Create the 'ensure' class. This is a separate method so other types
# can easily call it and create their own 'ensure' values.
def self.ensurable(&block)
if block_given?
self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block)
else
self.newproperty(:ensure, :parent => Puppet::Property::Ensure) do
self.defaultvalues
end
end
end
# Should we add the 'ensure' property to this class?
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)
}
ens
end
def self.apply_to_device
@apply_to = :device
end
def self.apply_to_host
@apply_to = :host
end
def self.apply_to_all
@apply_to = :both
end
def self.apply_to
@apply_to ||= :host
end
def self.can_apply_to(target)
[ target == :device ? :device : :host, :both ].include?(apply_to)
end
# Deal with any options passed into parameters.
def self.handle_param_options(name, options)
# If it's a boolean parameter, create a method to test the value easily
if options[:boolean]
define_method(name.to_s + "?") do
val = self[name]
if val == :true or val == true
return true
end
end
end
end
# Is the parameter in question a meta-parameter?
def self.metaparam?(param)
@@metaparamhash.include?(symbolize(param))
end
# Find the metaparameter class associated with a given metaparameter name.
def self.metaparamclass(name)
@@metaparamhash[symbolize(name)]
end
def self.metaparams
@@metaparams.collect { |param| param.name }
end
def self.metaparamdoc(metaparam)
@@metaparamhash[metaparam].doc
end
# Create a new metaparam. Requires a block and a name, stores it in the
# @parameters array, and does some basic checking on it.
def self.newmetaparam(name, options = {}, &block)
@@metaparams ||= []
@@metaparamhash ||= {}
name = symbolize(name)
param = genclass(
name,
:parent => options[:parent] || Puppet::Parameter,
:prefix => "MetaParam",
:hash => @@metaparamhash,
:array => @@metaparams,
:attributes => options[:attributes],
&block
)
# Grr.
param.required_features = options[:required_features] if options[:required_features]
handle_param_options(name, options)
param.metaparam = true
param
end
def self.key_attribute_parameters
@key_attribute_parameters ||= (
params = @parameters.find_all { |param|
param.isnamevar? or param.name == :name
}
)
end
def self.key_attributes
key_attribute_parameters.collect { |p| p.name }
end
def self.title_patterns
case key_attributes.length
when 0; []
when 1;
identity = lambda {|x| x}
[ [ /(.*)/m, [ [key_attributes.first, identity ] ] ] ]
else
raise Puppet::DevError,"you must specify title patterns when there are two or more key attributes"
end
end
def uniqueness_key
self.class.key_attributes.sort_by { |attribute_name| attribute_name.to_s }.map{ |attribute_name| self[attribute_name] }
end
# Create a new parameter. Requires a block and a name, stores it in the
# @parameters array, and does some basic checking on it.
def self.newparam(name, options = {}, &block)
options[:attributes] ||= {}
param = genclass(
name,
:parent => options[:parent] || Puppet::Parameter,
:attributes => options[:attributes],
:block => block,
:prefix => "Parameter",
:array => @parameters,
:hash => @paramhash
)
handle_param_options(name, options)
# Grr.
param.required_features = options[:required_features] if options[:required_features]
param.isnamevar if options[:namevar]
param
end
def self.newstate(name, options = {}, &block)
Puppet.warning "newstate() has been deprecrated; use newproperty(#{name})"
newproperty(name, options, &block)
end
# Create a new property. The first parameter must be the name of the property;
# this is how users will refer to the property when creating new instances.
# The second parameter is a hash of options; the options are:
# * <tt>:parent</tt>: The parent class for the property. Defaults to Puppet::Property.
# * <tt>:retrieve</tt>: The method to call on the provider or @parent object (if
# the provider is not set) to retrieve the current value.
def self.newproperty(name, options = {}, &block)
name = symbolize(name)
# This is here for types that might still have the old method of defining
# a parent class.
unless options.is_a? Hash
raise Puppet::DevError,
"Options must be a hash, not #{options.inspect}"
end
raise Puppet::DevError, "Class #{self.name} already has a property named #{name}" if @validproperties.include?(name)
if parent = options[:parent]
options.delete(:parent)
else
parent = Puppet::Property
end
# We have to create our own, new block here because we want to define
# an initial :retrieve method, if told to, and then eval the passed
# block if available.
prop = genclass(name, :parent => parent, :hash => @validproperties, :attributes => options) do
# If they've passed a retrieve method, then override the retrieve
# method on the class.
if options[:retrieve]
define_method(:retrieve) do
provider.send(options[:retrieve])
end
end
class_eval(&block) if block
end
# If it's the 'ensure' property, always put it first.
if name == :ensure
@properties.unshift prop
else
@properties << prop
end
prop
end
def self.paramdoc(param)
@paramhash[param].doc
end
# Return the parameter names
def self.parameters
return [] unless defined?(@parameters)
@parameters.collect { |klass| klass.name }
end
# Find the parameter class associated with a given parameter name.
def self.paramclass(name)
@paramhash[name]
end
# Return the property class associated with a name
def self.propertybyname(name)
@validproperties[name]
end
def self.validattr?(name)
name = symbolize(name)
return true if name == :name
@validattrs ||= {}
unless @validattrs.include?(name)
@validattrs[name] = !!(self.validproperty?(name) or self.validparameter?(name) or self.metaparam?(name))
end
@validattrs[name]
end
# does the name reflect a valid property?
def self.validproperty?(name)
name = symbolize(name)
@validproperties.include?(name) && @validproperties[name]
end
# Return the list of validproperties
def self.validproperties
return {} unless defined?(@parameters)
@validproperties.keys
end
# does the name reflect a valid parameter?
def self.validparameter?(name)
raise Puppet::DevError, "Class #{self} has not defined parameters" unless defined?(@parameters)
!!(@paramhash.include?(name) or @@metaparamhash.include?(name))
end
# This is a forward-compatibility method - it's the validity interface we'll use in Puppet::Resource.
def self.valid_parameter?(name)
validattr?(name)
end
# Return either the attribute alias or the attribute.
def attr_alias(name)
name = symbolize(name)
if synonym = self.class.attr_alias(name)
return synonym
else
return name
end
end
# Are we deleting this resource?
def deleting?
obj = @parameters[:ensure] and obj.should == :absent
end
# Create a new property if it is valid but doesn't exist
# Returns: true if a new parameter was added, false otherwise
def add_property_parameter(prop_name)
if self.class.validproperty?(prop_name) && !@parameters[prop_name]
self.newattr(prop_name)
return true
end
false
end
#
# The name_var is the key_attribute in the case that there is only one.
#
def name_var
key_attributes = self.class.key_attributes
(key_attributes.length == 1) && key_attributes.first
end
# abstract accessing parameters and properties, and normalize
# access to always be symbols, not strings
# This returns a value, not an object. It returns the 'is'
# value, but you can also specifically return 'is' and 'should'
# values using 'object.is(:property)' or 'object.should(:property)'.
def [](name)
name = attr_alias(name)
fail("Invalid parameter #{name}(#{name.inspect})") unless self.class.validattr?(name)
if name == :name && nv = name_var
name = nv
end
if obj = @parameters[name]
# Note that if this is a property, then the value is the "should" value,
# not the current value.
obj.value
else
return nil
end
end
# Abstract setting parameters and properties, and normalize
# access to always be symbols, not strings. This sets the 'should'
# value on properties, and otherwise just sets the appropriate parameter.
def []=(name,value)
name = attr_alias(name)
fail("Invalid parameter #{name}") unless self.class.validattr?(name)
if name == :name && nv = name_var
name = nv
end
raise Puppet::Error.new("Got nil value for #{name}") if value.nil?
property = self.newattr(name)
if property
begin
# make sure the parameter doesn't have any errors
property.value = value
rescue => detail
error = Puppet::Error.new("Parameter #{name} failed: #{detail}")
error.set_backtrace(detail.backtrace)
raise error
end
end
nil
end
# remove a property from the object; useful in testing or in cleanup
# when an error has been encountered
def delete(attr)
attr = symbolize(attr)
if @parameters.has_key?(attr)
@parameters.delete(attr)
else
raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
end
end
# iterate across the existing properties
def eachproperty
# properties is a private method
properties.each { |property|
yield property
}
end
# Create a transaction event. Called by Transaction or by
# a property.
def event(options = {})
Puppet::Transaction::Event.new({:resource => self, :file => file, :line => line, :tags => tags}.merge(options))
end
# retrieve the 'should' value for a specified property
def should(name)
name = attr_alias(name)
(prop = @parameters[name] and prop.is_a?(Puppet::Property)) ? prop.should : nil
end
# Create the actual attribute instance. Requires either the attribute
# name or class as the first argument, then an optional hash of
# attributes to set during initialization.
def newattr(name)
if name.is_a?(Class)
klass = name
name = klass.name
end
unless klass = self.class.attrclass(name)
raise Puppet::Error, "Resource type #{self.class.name} does not support parameter #{name}"
end
if provider and ! provider.class.supports_parameter?(klass)
missing = klass.required_features.find_all { |f| ! provider.class.feature?(f) }
info "Provider %s does not support features %s; not managing attribute %s" % [provider.class.name, missing.join(", "), name]
return nil
end
return @parameters[name] if @parameters.include?(name)
@parameters[name] = klass.new(:resource => self)
end
# return the value of a parameter
def parameter(name)
@parameters[name.to_sym]
end
def parameters
@parameters.dup
end
# Is the named property defined?
def propertydefined?(name)
name = name.intern unless name.is_a? Symbol
@parameters.include?(name)
end
# Return an actual property instance by name; to return the value, use 'resource[param]'
# LAK:NOTE(20081028) Since the 'parameter' method is now a superset of this method,
# this one should probably go away at some point.
def property(name)
(obj = @parameters[symbolize(name)] and obj.is_a?(Puppet::Property)) ? obj : nil
end
# For any parameters or properties that have defaults and have not yet been
# set, set them now. This method can be handed a list of attributes,
# and if so it will only set defaults for those attributes.
def set_default(attr)
return unless klass = self.class.attrclass(attr)
return unless klass.method_defined?(:default)
return if @parameters.include?(klass.name)
return unless parameter = newattr(klass.name)
if value = parameter.default and ! value.nil?
parameter.value = value
else
@parameters.delete(parameter.name)
end
end
# Convert our object to a hash. This just includes properties.
def to_hash
rethash = {}
@parameters.each do |name, obj|
rethash[name] = obj.value
end
rethash
end
def type
self.class.name
end
# Return a specific value for an attribute.
def value(name)
name = attr_alias(name)
(obj = @parameters[name] and obj.respond_to?(:value)) ? obj.value : nil
end
def version
return 0 unless catalog
catalog.version
end
# Return all of the property objects, in the order specified in the
# class.
def properties
self.class.properties.collect { |prop| @parameters[prop.name] }.compact
end
# Is this type's name isomorphic with the object? That is, if the
# name conflicts, does it necessarily mean that the objects conflict?
# Defaults to true.
def self.isomorphic?
if defined?(@isomorphic)
return @isomorphic
else
return true
end
end
def isomorphic?
self.class.isomorphic?
end
# is the instance a managed instance? A 'yes' here means that
# the instance was created from the language, vs. being created
# in order resolve other questions, such as finding a package
# in a list
def managed?
# Once an object is managed, it always stays managed; but an object
# that is listed as unmanaged might become managed later in the process,
# so we have to check that every time
if @managed
return @managed
else
@managed = false
properties.each { |property|
s = property.should
if s and ! property.class.unmanaged
@managed = true
break
end
}
return @managed
end
end
###############################
# Code related to the container behaviour.
def depthfirst?
false
end
# Remove an object. The argument determines whether the object's
# subscriptions get eliminated, too.
def remove(rmdeps = true)
# This is hackish (mmm, cut and paste), but it works for now, and it's
# better than warnings.
@parameters.each do |name, obj|
obj.remove
end
@parameters.clear
@parent = nil
# Remove the reference to the provider.
if self.provider
@provider.clear
@provider = nil
end
end
###############################
# Code related to evaluating the resources.
# Flush the provider, if it supports it. This is called by the
# transaction.
def flush
self.provider.flush if self.provider and self.provider.respond_to?(:flush)
end
# if all contained objects are in sync, then we're in sync
# FIXME I don't think this is used on the type instances any more,
# it's really only used for testing
def insync?(is)
insync = true
if property = @parameters[:ensure]
unless is.include? property
raise Puppet::DevError,
"The is value is not in the is array for '#{property.name}'"
end
ensureis = is[property]
if property.safe_insync?(ensureis) and property.should == :absent
return true
end
end
properties.each { |property|
unless is.include? property
raise Puppet::DevError,
"The is value is not in the is array for '#{property.name}'"
end
propis = is[property]
unless property.safe_insync?(propis)
property.debug("Not in sync: #{propis.inspect} vs #{property.should.inspect}")
insync = false
#else
# property.debug("In sync")
end
}
#self.debug("#{self} sync status is #{insync}")
insync
end
# retrieve the current value of all contained properties
def retrieve
fail "Provider #{provider.class.name} is not functional on this host" if self.provider.is_a?(Puppet::Provider) and ! provider.class.suitable?
result = Puppet::Resource.new(type, title)
# Provide the name, so we know we'll always refer to a real thing
result[:name] = self[:name] unless self[:name] == title
if ensure_prop = property(:ensure) or (self.class.validattr?(:ensure) and ensure_prop = newattr(:ensure))
result[:ensure] = ensure_state = ensure_prop.retrieve
else
ensure_state = nil
end
properties.each do |property|
next if property.name == :ensure
if ensure_state == :absent
result[property] = :absent
else
result[property] = property.retrieve
end
end
result
end
def retrieve_resource
resource = retrieve
resource = Resource.new(type, title, :parameters => resource) if resource.is_a? Hash
resource
end
# Get a hash of the current properties. Returns a hash with
# the actual property instance as the key and the current value
# as the, um, value.
def currentpropvalues
# It's important to use the 'properties' method here, as it follows the order
# in which they're defined in the class. It also guarantees that 'ensure'
# is the first property, which is important for skipping 'retrieve' on
# all the properties if the resource is absent.
ensure_state = false
return properties.inject({}) do | prophash, property|
if property.name == :ensure
ensure_state = property.retrieve
prophash[property] = ensure_state
else
if ensure_state == :absent
prophash[property] = :absent
else
prophash[property] = property.retrieve
end
end
prophash
end
end
# Are we running in noop mode?
def noop?
# If we're not a host_config, we're almost certainly part of
# Settings, and we want to ignore 'noop'
return false if catalog and ! catalog.host_config?
if defined?(@noop)
@noop
else
Puppet[:noop]
end
end
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"
@objects[name] || @aliases[name]
end
# add an instance by name to the class list of instances
def self.[]=(name,object)
raise "Global resource storage is deprecated"
newobj = nil
if object.is_a?(Puppet::Type)
newobj = object
else
raise Puppet::DevError, "must pass a Puppet::Type object"
end
if exobj = @objects[name] and self.isomorphic?
msg = "Object '#{newobj.class.name}[#{name}]' already exists"
msg += ("in file #{object.file} at line #{object.line}") if exobj.file and exobj.line
msg += ("and cannot be redefined in file #{object.file} at line #{object.line}") if object.file and object.line
error = Puppet::Error.new(msg)
raise error
else
#Puppet.info("adding %s of type %s to class list" %
# [name,object.class])
@objects[name] = newobj
end
end
# Create an alias. We keep these in a separate hash so that we don't encounter
# the objects multiple times when iterating over them.
def self.alias(name, obj)
raise "Global resource aliasing is deprecated"
if @objects.include?(name)
unless @objects[name] == obj
raise Puppet::Error.new(
"Cannot create alias #{name}: object already exists"
)
end
end
if @aliases.include?(name)
unless @aliases[name] == obj
raise Puppet::Error.new(
"Object #{@aliases[name].name} already has alias #{name}"
)
end
end
@aliases[name] = obj
end
# remove all of the instances of a single type
def self.clear
raise "Global resource removal is deprecated"
if defined?(@objects)
@objects.each do |name, obj|
obj.remove(true)
end
@objects.clear
end
@aliases.clear if defined?(@aliases)
end
# Force users to call this, so that we can merge objects if
# necessary.
def self.create(args)
# LAK:DEP Deprecation notice added 12/17/2008
Puppet.warning "Puppet::Type.create is deprecated; use Puppet::Type.new"
new(args)
end
# remove a specified object
def self.delete(resource)
raise "Global resource removal is deprecated"
return unless defined?(@objects)
@objects.delete(resource.title) if @objects.include?(resource.title)
@aliases.delete(resource.title) if @aliases.include?(resource.title)
if @aliases.has_value?(resource)
names = []
@aliases.each do |name, otherres|
if otherres == resource
names << name
end
end
names.each { |name| @aliases.delete(name) }
end
end
# iterate across each of the type's instances
def self.each
raise "Global resource iteration is deprecated"
return unless defined?(@objects)
@objects.each { |name,instance|
yield instance
}
end
# does the type have an object with the given name?
def self.has_key?(name)
raise "Global resource access is deprecated"
@objects.has_key?(name)
end
# Retrieve all known instances. Either requires providers or must be overridden.
def self.instances
raise Puppet::DevError, "#{self.name} has no providers and has not overridden 'instances'" if provider_hash.empty?
# Put the default provider first, then the rest of the suitable providers.
provider_instances = {}
providers_by_source.collect do |provider|
all_properties = self.properties.find_all do |property|
provider.supports_parameter?(property)
end.collect do |property|
property.name
end
provider.instances.collect do |instance|
# We always want to use the "first" provider instance we find, unless the resource
# is already managed and has a different provider set
if other = provider_instances[instance.name]
Puppet.warning "%s %s found in both %s and %s; skipping the %s version" %
[self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
next
end
provider_instances[instance.name] = instance
result = new(:name => instance.name, :provider => instance)
properties.each { |name| result.newattr(name) }
result
end
end.flatten.compact
end
# Return a list of one suitable provider per source, with the default provider first.
def self.providers_by_source
# Put the default provider first, then the rest of the suitable providers.
sources = []
[defaultprovider, suitableprovider].flatten.uniq.collect do |provider|
next if sources.include?(provider.source)
sources << provider.source
provider
end.compact
end
# Convert a simple hash into a Resource instance.
def self.hash2resource(hash)
hash = hash.inject({}) { |result, ary| result[ary[0].to_sym] = ary[1]; result }
title = hash.delete(:title)
title ||= hash[:name]
title ||= hash[key_attributes.first] if key_attributes.length == 1
raise Puppet::Error, "Title or name must be provided" unless title
# Now create our resource.
resource = Puppet::Resource.new(self.name, title)
[:catalog].each do |attribute|
if value = hash[attribute]
hash.delete(attribute)
resource.send(attribute.to_s + "=", value)
end
end
hash.each do |param, value|
resource[param] = value
end
resource
end
# Create the path for logging and such.
def pathbuilder
if p = parent
[p.pathbuilder, self.ref].flatten
else
[self.ref]
end
end
###############################
# Add all of the meta parameters.
newmetaparam(:noop) do
desc "Boolean flag indicating whether work should actually
be done."
newvalues(:true, :false)
munge do |value|
case value
when true, :true, "true"; @resource.noop = true
when false, :false, "false"; @resource.noop = false
end
end
end
newmetaparam(:schedule) do
desc "On what schedule the object should be managed. You must create a
schedule object, and then reference the name of that object to use
that for your schedule:
schedule { 'daily':
period => daily,
range => \"2-4\"
}
exec { \"/usr/bin/apt-get update\":
schedule => 'daily'
}
The creation of the schedule object does not need to appear in the
configuration before objects that use it."
end
newmetaparam(:audit) do
desc "Marks a subset of this resource's unmanaged attributes for auditing. Accepts an
attribute name, an array of attribute names, or `all`.
Auditing a resource attribute has two effects: First, whenever a catalog
is applied with puppet apply or puppet agent, Puppet will check whether
that attribute of the resource has been modified, comparing its current
value to the previous run; any change will be logged alongside any actions
performed by Puppet while applying the catalog.
Secondly, marking a resource attribute for auditing will include that
attribute in inspection reports generated by puppet inspect; see the
puppet inspect documentation for more details.
Managed attributes for a resource can also be audited, but note that
changes made by Puppet will be logged as additional modifications. (I.e.
if a user manually edits a file whose contents are audited and managed,
puppet agent's next two runs will both log an audit notice: the first run
will log the user's edit and then revert the file to the desired state,
and the second run will log the edit made by Puppet.)"
validate do |list|
list = Array(list).collect {|p| p.to_sym}
unless list == [:all]
list.each do |param|
next if @resource.class.validattr?(param)
fail "Cannot audit #{param}: not a valid attribute for #{resource}"
end
end
end
munge do |args|
properties_to_audit(args).each do |param|
next unless resource.class.validproperty?(param)
resource.newattr(param)
end
end
def all_properties
resource.class.properties.find_all do |property|
resource.provider.nil? or resource.provider.class.supports_parameter?(property)
end.collect do |property|
property.name
end
end
def properties_to_audit(list)
if !list.kind_of?(Array) && list.to_sym == :all
list = all_properties
else
list = Array(list).collect { |p| p.to_sym }
end
end
end
newmetaparam(:check) do
desc "Audit specified attributes of resources over time, and report if any have changed.
This parameter has been deprecated in favor of 'audit'."
munge do |args|
resource.warning "'check' attribute is deprecated; use 'audit' instead"
resource[:audit] = args
end
end
newmetaparam(:loglevel) do
desc "Sets the level that information will be logged.
The log levels have the biggest impact when logs are sent to
syslog (which is currently the default)."
defaultto :notice
newvalues(*Puppet::Util::Log.levels)
newvalues(:verbose)
munge do |loglevel|
val = super(loglevel)
if val == :verbose
val = :info
end
val
end
end
newmetaparam(:alias) do
desc "Creates an alias for the object. Puppet uses this internally when you
provide a symbolic title:
file { 'sshdconfig':
path => $operatingsystem ? {
solaris => \"/usr/local/etc/ssh/sshd_config\",
default => \"/etc/ssh/sshd_config\"
},
source => \"...\"
}
service { 'sshd':
subscribe => File['sshdconfig']
}
When you use this feature, the parser sets `sshdconfig` as the title,
and the library sets that as an alias for the file so the dependency
lookup in `Service['sshd']` works. You can use this metaparameter yourself,
but note that only the library can use these aliases; for instance,
the following code will not work:
file { \"/etc/ssh/sshd_config\":
owner => root,
group => root,
alias => 'sshdconfig'
}
file { 'sshdconfig':
mode => 644
}
There's no way here for the Puppet parser to know that these two stanzas
should be affecting the same file.
See the [Language Guide](http://docs.puppetlabs.com/guides/language_guide.html) for more information.
"
munge do |aliases|
aliases = [aliases] unless aliases.is_a?(Array)
raise(ArgumentError, "Cannot add aliases without a catalog") unless @resource.catalog
aliases.each do |other|
if obj = @resource.catalog.resource(@resource.class.name, other)
unless obj.object_id == @resource.object_id
self.fail("#{@resource.title} can not create alias #{other}: object already exists")
end
next
end
# Newschool, add it to the catalog.
@resource.catalog.alias(@resource, other)
end
end
end
newmetaparam(:tag) do
desc "Add the specified tags to the associated resource. While all resources
are automatically tagged with as much information as possible
(e.g., each class and definition containing the resource), it can
be useful to add your own tags to a given resource.
- Tags are currently useful for things like applying a subset of a
- host's configuration:
+ Multiple tags can be specified as an array:
- puppet agent --test --tags mytag
+ file {'/etc/hosts':
+ ensure => file,
+ source => 'puppet:///modules/site/hosts',
+ mode => 0644,
+ tag => ['bootstrap', 'minimumrun', 'mediumrun'],
+ }
+
+ Tags are useful for things like applying a subset of a host's configuration
+ with [the `tags` setting](/references/latest/configuration.html#tags):
+
+ puppet agent --test --tags bootstrap
- This way, when you're testing a configuration you can run just the
- portion you're testing."
+ This way, you can easily isolate the portion of the configuration you're
+ trying to test."
munge do |tags|
tags = [tags] unless tags.is_a? Array
tags.each do |tag|
@resource.tag(tag)
end
end
end
class RelationshipMetaparam < Puppet::Parameter
class << self
attr_accessor :direction, :events, :callback, :subclasses
end
@subclasses = []
def self.inherited(sub)
@subclasses << sub
end
def munge(references)
references = [references] unless references.is_a?(Array)
references.collect do |ref|
if ref.is_a?(Puppet::Resource)
ref
else
Puppet::Resource.new(ref)
end
end
end
def validate_relationship
@value.each do |ref|
unless @resource.catalog.resource(ref.to_s)
description = self.class.direction == :in ? "dependency" : "dependent"
fail "Could not find #{description} #{ref} for #{resource.ref}"
end
end
end
# Create edges from each of our relationships. :in
# relationships are specified by the event-receivers, and :out
# relationships are specified by the event generator. This
# way 'source' and 'target' are consistent terms in both edges
# and events -- that is, an event targets edges whose source matches
# the event's source. The direction of the relationship determines
# which resource is applied first and which resource is considered
# to be the event generator.
def to_edges
@value.collect do |reference|
reference.catalog = resource.catalog
# Either of the two retrieval attempts could have returned
# nil.
unless related_resource = reference.resolve
self.fail "Could not retrieve dependency '#{reference}' of #{@resource.ref}"
end
# Are we requiring them, or vice versa? See the method docs
# for futher info on this.
if self.class.direction == :in
source = related_resource
target = @resource
else
source = @resource
target = related_resource
end
if method = self.class.callback
subargs = {
:event => self.class.events,
:callback => method
}
self.debug("subscribes to #{related_resource.ref}")
else
# If there's no callback, there's no point in even adding
# a label.
subargs = nil
self.debug("requires #{related_resource.ref}")
end
rel = Puppet::Relationship.new(source, target, subargs)
end
end
end
def self.relationship_params
RelationshipMetaparam.subclasses
end
# Note that the order in which the relationships params is defined
# matters. The labelled params (notify and subcribe) must be later,
# so that if both params are used, those ones win. It's a hackish
# solution, but it works.
newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do
desc "References to one or more objects that this object depends on.
This is used purely for guaranteeing that changes to required objects
happen before the dependent object. For instance:
# Create the destination directory before you copy things down
file { \"/usr/local/scripts\":
ensure => directory
}
file { \"/usr/local/scripts/myscript\":
source => \"puppet://server/module/myscript\",
mode => 755,
require => File[\"/usr/local/scripts\"]
}
Multiple dependencies can be specified by providing a comma-seperated list
of resources, enclosed in square brackets:
require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ]
Note that Puppet will autorequire everything that it can, and
there are hooks in place so that it's easy for resources to add new
ways to autorequire objects, so if you think Puppet could be
smarter here, let us know.
In fact, the above code was redundant --- Puppet will autorequire
any parent directories that are being managed; it will
automatically realize that the parent directory should be created
before the script is pulled down.
Currently, exec resources will autorequire their CWD (if it is
specified) plus any fully qualified paths that appear in the
command. For instance, if you had an `exec` command that ran
the `myscript` mentioned above, the above code that pulls the
file down would be automatically listed as a requirement to the
`exec` code, so that you would always be running againts the
most recent version.
"
end
newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do
desc "References to one or more objects that this object depends on. This
metaparameter creates a dependency relationship like **require,**
and also causes the dependent object to be refreshed when the
subscribed object is changed. For instance:
class nagios {
file { 'nagconf':
path => \"/etc/nagios/nagios.conf\"
source => \"puppet://server/module/nagios.conf\",
}
service { 'nagios':
ensure => running,
subscribe => File['nagconf']
}
}
Currently the `exec`, `mount` and `service` types support
refreshing.
"
end
newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do
desc %{References to one or more objects that depend on this object. This
parameter is the opposite of **require** --- it guarantees that
the specified object is applied later than the specifying object:
file { "/var/nagios/configuration":
source => "...",
recurse => true,
before => Exec["nagios-rebuid"]
}
exec { "nagios-rebuild":
command => "/usr/bin/make",
cwd => "/var/nagios/configuration"
}
This will make sure all of the files are up to date before the
make command is run.}
end
newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do
desc %{References to one or more objects that depend on this object. This
parameter is the opposite of **subscribe** --- it creates a
dependency relationship like **before,** and also causes the
dependent object(s) to be refreshed when this object is changed. For
instance:
file { "/etc/sshd_config":
source => "....",
notify => Service['sshd']
}
service { 'sshd':
ensure => running
}
This will restart the sshd service if the sshd config file changes.}
end
newmetaparam(:stage) do
desc %{Which run stage a given resource should reside in. This just creates
a dependency on or from the named milestone. For instance, saying that
this is in the 'bootstrap' stage creates a dependency on the 'bootstrap'
milestone.
By default, all classes get directly added to the
'main' stage. You can create new stages as resources:
stage { ['pre', 'post']: }
To order stages, use standard relationships:
stage { 'pre': before => Stage['main'] }
Or use the new relationship syntax:
Stage['pre'] -> Stage['main'] -> Stage['post']
Then use the new class parameters to specify a stage:
class { 'foo': stage => 'pre' }
Stages can only be set on classes, not individual resources. This will
fail:
file { '/foo': stage => 'pre', ensure => file }
}
end
###############################
# All of the provider plumbing for the resource types.
require 'puppet/provider'
require 'puppet/util/provider_features'
# Add the feature handling module.
extend Puppet::Util::ProviderFeatures
attr_reader :provider
# the Type class attribute accessors
class << self
attr_accessor :providerloader
attr_writer :defaultprovider
end
# Find the default provider.
def self.defaultprovider
unless @defaultprovider
suitable = suitableprovider
# Find which providers are a default for this system.
defaults = suitable.find_all { |provider| provider.default? }
# If we don't have any default we use suitable providers
defaults = suitable if defaults.empty?
max = defaults.collect { |provider| provider.specificity }.max
defaults = defaults.find_all { |provider| provider.specificity == max }
retval = nil
if defaults.length > 1
Puppet.warning(
"Found multiple default providers for #{self.name}: #{defaults.collect { |i| i.name.to_s }.join(", ")}; using #{defaults[0].name}"
)
retval = defaults.shift
elsif defaults.length == 1
retval = defaults.shift
else
raise Puppet::DevError, "Could not find a default provider for #{self.name}"
end
@defaultprovider = retval
end
@defaultprovider
end
def self.provider_hash_by_type(type)
@provider_hashes ||= {}
@provider_hashes[type] ||= {}
end
def self.provider_hash
Puppet::Type.provider_hash_by_type(self.name)
end
# Retrieve a provider by name.
def self.provider(name)
name = Puppet::Util.symbolize(name)
# If we don't have it yet, try loading it.
@providerloader.load(name) unless provider_hash.has_key?(name)
provider_hash[name]
end
# Just list all of the providers.
def self.providers
provider_hash.keys
end
def self.validprovider?(name)
name = Puppet::Util.symbolize(name)
(provider_hash.has_key?(name) && provider_hash[name].suitable?)
end
# Create a new provider of a type. This method must be called
# directly on the type that it's implementing.
def self.provide(name, options = {}, &block)
name = Puppet::Util.symbolize(name)
if unprovide(name)
Puppet.debug "Reloading #{name} #{self.name} provider"
end
parent = if pname = options[:parent]
options.delete(:parent)
if pname.is_a? Class
pname
else
if provider = self.provider(pname)
provider
else
raise Puppet::DevError,
"Could not find parent provider #{pname} of #{name}"
end
end
else
Puppet::Provider
end
options[:resource_type] ||= self
self.providify
provider = genclass(
name,
:parent => parent,
:hash => provider_hash,
:prefix => "Provider",
:block => block,
:include => feature_module,
:extend => feature_module,
:attributes => options
)
provider
end
# Make sure we have a :provider parameter defined. Only gets called if there
# are providers.
def self.providify
return if @paramhash.has_key? :provider
newparam(:provider) do
# We're using a hacky way to get the name of our type, since there doesn't
# seem to be a correct way to introspect this at the time this code is run.
# We expect that the class in which this code is executed will be something
# like Puppet::Type::Ssh_authorized_key::ParameterProvider.
desc <<-EOT
The specific backend to use for this `#{self.to_s.split('::')[2].downcase}`
resource. You will seldom need to specify this --- Puppet will usually
discover the appropriate provider for your platform.
EOT
# This is so we can refer back to the type to get a list of
# providers for documentation.
class << self
attr_accessor :parenttype
end
# We need to add documentation for each provider.
def self.doc
@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")
end
defaultto {
@resource.class.defaultprovider.name
}
validate do |provider_class|
provider_class = provider_class[0] if provider_class.is_a? Array
provider_class = provider_class.class.name if provider_class.is_a?(Puppet::Provider)
unless provider = @resource.class.provider(provider_class)
raise ArgumentError, "Invalid #{@resource.class.name} provider '#{provider_class}'"
end
end
munge do |provider|
provider = provider[0] if provider.is_a? Array
provider = provider.intern if provider.is_a? String
@resource.provider = provider
if provider.is_a?(Puppet::Provider)
provider.class.name
else
provider
end
end
end.parenttype = self
end
def self.unprovide(name)
if @defaultprovider and @defaultprovider.name == name
@defaultprovider = nil
end
rmclass(name, :hash => provider_hash, :prefix => "Provider")
end
# Return an array of all of the suitable providers.
def self.suitableprovider
providerloader.loadall if provider_hash.empty?
provider_hash.find_all { |name, provider|
provider.suitable?
}.collect { |name, provider|
provider
}.reject { |p| p.name == :fake } # For testing
end
def provider=(name)
if name.is_a?(Puppet::Provider)
@provider = name
@provider.resource = self
elsif klass = self.class.provider(name)
@provider = klass.new(self)
else
raise ArgumentError, "Could not find #{name} provider of #{self.class.name}"
end
end
###############################
# All of the relationship code.
# Specify a block for generating a list of objects to autorequire. This
# makes it so that you don't have to manually specify things that you clearly
# require.
def self.autorequire(name, &block)
@autorequires ||= {}
@autorequires[name] = block
end
# Yield each of those autorequires in turn, yo.
def self.eachautorequire
@autorequires ||= {}
@autorequires.each { |type, block|
yield(type, block)
}
end
# Figure out of there are any objects we can automatically add as
# dependencies.
def autorequire(rel_catalog = nil)
rel_catalog ||= catalog
raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog
reqs = []
self.class.eachautorequire { |type, block|
# Ignore any types we can't find, although that would be a bit odd.
next unless typeobj = Puppet::Type.type(type)
# Retrieve the list of names from the block.
next unless list = self.instance_eval(&block)
list = [list] unless list.is_a?(Array)
# Collect the current prereqs
list.each { |dep|
# Support them passing objects directly, to save some effort.
unless dep.is_a? Puppet::Type
# Skip autorequires that we aren't managing
unless dep = rel_catalog.resource(type, dep)
next
end
end
reqs << Puppet::Relationship.new(dep, self)
}
}
reqs
end
# Build the dependencies associated with an individual object.
def builddepends
# Handle the requires
self.class.relationship_params.collect do |klass|
if param = @parameters[klass.name]
param.to_edges
end
end.flatten.reject { |r| r.nil? }
end
# Define the initial list of tags.
def tags=(list)
tag(self.class.name)
tag(*list)
end
# Types (which map to resources in the languages) are entirely composed of
# attribute value pairs. Generally, Puppet calls any of these things an
# 'attribute', but these attributes always take one of three specific
# forms: parameters, metaparams, or properties.
# In naming methods, I have tried to consistently name the method so
# that it is clear whether it operates on all attributes (thus has 'attr' in
# the method name, or whether it operates on a specific type of attributes.
attr_writer :title
attr_writer :noop
include Enumerable
# class methods dealing with Type management
public
# the Type class attribute accessors
class << self
attr_reader :name
attr_accessor :self_refresh
include Enumerable, Puppet::Util::ClassGen
include Puppet::MetaType::Manager
include Puppet::Util
include Puppet::Util::Logging
end
# all of the variables that must be initialized for each subclass
def self.initvars
# all of the instances of this class
@objects = Hash.new
@aliases = Hash.new
@defaults = {}
@parameters ||= []
@validproperties = {}
@properties = []
@parameters = []
@paramhash = {}
@attr_aliases = {}
@paramdoc = Hash.new { |hash,key|
key = key.intern if key.is_a?(String)
if hash.include?(key)
hash[key]
else
"Param Documentation for #{key} not found"
end
}
@doc ||= ""
end
def self.to_s
if defined?(@name)
"Puppet::Type::#{@name.to_s.capitalize}"
else
super
end
end
# Create a block to validate that our object is set up entirely. This will
# be run before the object is operated on.
def self.validate(&block)
define_method(:validate, &block)
#@validate = block
end
# The catalog that this resource is stored in.
attr_accessor :catalog
# is the resource exported
attr_accessor :exported
# is the resource virtual (it should not :-))
attr_accessor :virtual
# create a log at specified level
def log(msg)
Puppet::Util::Log.create(
:level => @parameters[:loglevel].value,
:message => msg,
:source => self
)
end
# instance methods related to instance intrinsics
# e.g., initialize and name
public
attr_reader :original_parameters
# 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.
@parameters = {}
# Set the title first, so any failures print correctly.
if resource.type.to_s.downcase.to_sym == self.class.name
self.title = resource.title
else
# This should only ever happen for components
self.title = resource.ref
end
[:file, :line, :catalog, :exported, :virtual].each do |getter|
setter = getter.to_s + "="
if val = resource.send(getter)
self.send(setter, val)
end
end
@tags = resource.tags
@original_parameters = resource.to_hash
set_name(@original_parameters)
set_default(:provider)
set_parameters(@original_parameters)
self.validate if self.respond_to?(:validate)
end
private
# Set our resource's name.
def set_name(hash)
self[name_var] = hash.delete(name_var) if name_var
end
# Set all of the parameters from a hash, in the appropriate order.
def set_parameters(hash)
# Use the order provided by allattrs, but add in any
# extra attributes from the resource so we get failures
# on invalid attributes.
no_values = []
(self.class.allattrs + hash.keys).uniq.each do |attr|
begin
# Set any defaults immediately. This is mostly done so
# that the default provider is available for any other
# property validation.
if hash.has_key?(attr)
self[attr] = hash[attr]
else
no_values << attr
end
rescue ArgumentError, Puppet::Error, TypeError
raise
rescue => detail
error = Puppet::DevError.new( "Could not set #{attr} on #{self.class.name}: #{detail}")
error.set_backtrace(detail.backtrace)
raise error
end
end
no_values.each do |attr|
set_default(attr)
end
end
public
# Set up all of our autorequires.
def finish
# Make sure all of our relationships are valid. Again, must be done
# when the entire catalog is instantiated.
self.class.relationship_params.collect do |klass|
if param = @parameters[klass.name]
param.validate_relationship
end
end.flatten.reject { |r| r.nil? }
end
# For now, leave the 'name' method functioning like it used to. Once 'title'
# works everywhere, I'll switch it.
def name
self[:name]
end
# Look up our parent in the catalog, if we have one.
def parent
return nil unless catalog
unless defined?(@parent)
if parents = catalog.adjacent(self, :direction => :in)
# We should never have more than one parent, so let's just ignore
# it if we happen to.
@parent = parents.shift
else
@parent = nil
end
end
@parent
end
# Return the "type[name]" style reference.
def ref
"#{self.class.name.to_s.capitalize}[#{self.title}]"
end
def self_refresh?
self.class.self_refresh
end
# Mark that we're purging.
def purging
@purging = true
end
# Is this resource being purged? Used by transactions to forbid
# deletion when there are dependencies.
def purging?
if defined?(@purging)
@purging
else
false
end
end
# Retrieve the title of an object. If no title was set separately,
# then use the object's name.
def title
unless @title
if self.class.validparameter?(name_var)
@title = self[:name]
elsif self.class.validproperty?(name_var)
@title = self.should(name_var)
else
self.devfail "Could not find namevar #{name_var} for #{self.class.name}"
end
end
@title
end
# convert to a string
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
@parameters.each do |name, param|
# Avoid adding each instance name twice
next if param.class.isnamevar? and param.value == self.title
# We've already got property values
next if param.is_a?(Puppet::Property)
trans[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
end
def virtual?; !!@virtual; end
def exported?; !!@exported; end
def appliable_to_device?
self.class.can_apply_to(:device)
end
def appliable_to_host?
self.class.can_apply_to(:host)
end
end
end
require 'puppet/provider'
# Always load these types.
Puppet::Type.type(:component)
diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb
index f02cfe6e2..cc2ca6b1d 100644
--- a/lib/puppet/type/augeas.rb
+++ b/lib/puppet/type/augeas.rb
@@ -1,184 +1,218 @@
#
# Copyright 2011 Bryan Kearney <bkearney@redhat.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Puppet::Type.newtype(:augeas) do
include Puppet::Util
feature :parse_commands, "Parse the command string"
feature :need_to_run?, "If the command should run"
feature :execute_changes, "Actually make the changes"
@doc = <<-EOT
- Apply the changes (single or array of changes) to the filesystem
- via the augeas tool.
+ Apply a change or an array of changes to the filesystem
+ using the augeas tool.
Requires:
- - augeas to be installed (http://www.augeas.net)
- - ruby-augeas bindings
+ - [Augeas](http://www.augeas.net)
+ - The ruby-augeas bindings
Sample usage with a string:
augeas{"test1" :
context => "/files/etc/sysconfig/firstboot",
changes => "set RUN_FIRSTBOOT YES",
onlyif => "match other_value size > 0",
}
Sample usage with an array and custom lenses:
augeas{"jboss_conf":
- context => "/files",
- changes => [
- "set etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress",
- "set etc/jbossas/jbossas.conf/JAVA_HOME /usr",
- ],
+ context => "/files",
+ changes => [
+ "set etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress",
+ "set etc/jbossas/jbossas.conf/JAVA_HOME /usr",
+ ],
load_path => "$/usr/share/jbossas/lenses",
}
EOT
newparam (:name) do
- desc "The name of this task. Used for uniqueness"
+ desc "The name of this task. Used for uniqueness."
isnamevar
end
newparam (:context) do
- desc "Optional context path. This value is prepended to the paths of all changes if the path is relative. If INCL is set, defaults to '/files' + INCL, otherwise the empty string"
+ desc "Optional context path. This value is prepended to the paths of all
+ changes if the path is relative. If the `incl` parameter is set,
+ defaults to `/files + incl`; otherwise, defaults to the empty string."
defaultto ""
munge do |value|
if value.empty? and resource[:incl]
"/files" + resource[:incl]
else
value
end
end
end
newparam (:onlyif) do
desc "Optional augeas command and comparisons to control the execution of this type.
Supported onlyif syntax:
- get [AUGEAS_PATH] [COMPARATOR] [STRING]
- match [MATCH_PATH] size [COMPARATOR] [INT]
- match [MATCH_PATH] include [STRING]
- match [MATCH_PATH] not_include [STRING]
- match [MATCH_PATH] == [AN_ARRAY]
- match [MATCH_PATH] != [AN_ARRAY]
+ * `get <AUGEAS_PATH> <COMPARATOR> <STRING>`
+ * `match <MATCH_PATH> size <COMPARATOR> <INT>`
+ * `match <MATCH_PATH> include <STRING>`
+ * `match <MATCH_PATH> not_include <STRING>`
+ * `match <MATCH_PATH> == <AN_ARRAY>`
+ * `match <MATCH_PATH> != <AN_ARRAY>`
where:
- AUGEAS_PATH is a valid path scoped by the context
- MATCH_PATH is a valid match synatx scoped by the context
- COMPARATOR is in the set [> >= != == <= <]
- STRING is a string
- INT is a number
- AN_ARRAY is in the form ['a string', 'another']"
+ * `AUGEAS_PATH` is a valid path scoped by the context
+ * `MATCH_PATH` is a valid match synatx scoped by the context
+ * `COMPARATOR` is one of `>, >=, !=, ==, <=,` or `<`
+ * `STRING` is a string
+ * `INT` is a number
+ * `AN_ARRAY` is in the form `['a string', 'another']`"
defaultto ""
end
newparam(:changes) do
desc "The changes which should be applied to the filesystem. This
- can be either a string which contains a command or an array of commands.
- Commands supported are:
-
- set [PATH] [VALUE] Sets the value VALUE at loction PATH
- setm [PATH] [SUB] [VALUE] Sets multiple nodes matching SUB relative to PATH, to VALUE
- rm [PATH] Removes the node at location PATH
- remove [PATH] Synonym for rm
- clear [PATH] Sets the node at PATH to NULL, creating it if needed
- ins [LABEL] [WHERE] [PATH] Inserts an empty node LABEL either [WHERE={before|after}] PATH.
- insert [LABEL] [WHERE] [PATH] Synonym for ins
- mv [PATH] [PATH] Moves a node at PATH to the new location PATH
- move [PATH] [PATH] Synonym for mv
- defvar [NAME] [PATH] Sets Augeas variable $NAME to PATH
- defnode [NAME] [PATH] [VALUE] Sets Augeas variable $NAME to PATH, creating it with VALUE if needed
-
- If the parameter 'context' is set that value is prepended to a relative PATH"
+ can be a command or an array of commands. The following commands are supported:
+
+ `set <PATH> <VALUE>`
+ : Sets the value `VALUE` at loction `PATH`
+
+
+ `setm <PATH> <SUB> <VALUE>`
+ : Sets multiple nodes (matching `SUB` relative to `PATH`) to `VALUE`
+
+
+ `rm <PATH>`
+ : Removes the node at location `PATH`
+
+
+ `remove <PATH>`
+ : Synonym for `rm`
+
+
+ `clear <PATH>`
+ : Sets the node at `PATH` to `NULL`, creating it if needed
+
+
+ `ins <LABEL> (before|after) <PATH>`
+ : Inserts an empty node `LABEL` either before or after `PATH`.
+
+
+ `insert <LABEL> <WHERE> <PATH>`
+ : Synonym for `ins`
+
+
+ `mv <PATH> <OTHER PATH>`
+ : Moves a node at `PATH` to the new location `OTHER PATH`
+
+
+ `move <PATH> <OTHER PATH>`
+ : Synonym for `mv`
+
+
+ `defvar <NAME> <PATH>`
+ : Sets Augeas variable `$NAME` to `PATH`
+
+
+ `defnode <NAME> <PATH> <VALUE>`
+ : Sets Augeas variable `$NAME` to `PATH`, creating it with `VALUE` if needed
+
+ If the `context` parameter is set, that value is prepended to any relative `PATH`s."
end
newparam(:root) do
- desc "A file system path; all files loaded by Augeas are loaded underneath ROOT"
+ desc "A file system path; all files loaded by Augeas are loaded underneath `root`."
defaultto "/"
end
newparam(:load_path) do
- desc "Optional colon separated list of directories; these directories are searched for schema definitions"
+ desc "Optional colon-separated list of directories; these directories are searched for schema definitions."
defaultto ""
end
newparam(:force) do
desc "Optional command to force the augeas type to execute even if it thinks changes
- will not be made. This does not overide the only setting. If onlyif is set, then the
- foce setting will not override that result"
+ will not be made. This does not overide the `onlyif` parameter."
defaultto false
end
newparam(:type_check) do
- desc "Set to true if augeas should perform typechecking. Optional, defaults to false"
+ desc "Whether augeas should perform typechecking. Defaults to false."
newvalues(:true, :false)
defaultto :false
end
newparam(:lens) do
- desc "Use a specific lens, e.g. `Hosts.lns`. When this parameter is set, you must also set the incl parameter to indicate which file to load. Only that file will be loaded, which greatly speeds up execution of the type"
+ desc "Use a specific lens, e.g. `Hosts.lns`. When this parameter is set, you
+ must also set the `incl` parameter to indicate which file to load."
end
newparam(:incl) do
- desc "Load only a specific file, e.g. `/etc/hosts`. When this parameter is set, you must also set the lens parameter to indicate which lens to use."
+ desc "Load only a specific file, e.g. `/etc/hosts`. This can greatly speed
+ up the execution the resource. When this parameter is set, you must also
+ set the `lens` parameter to indicate which lens to use."
end
validate do
has_lens = !self[:lens].nil?
has_incl = !self[:incl].nil?
- self.fail "You must specify both the lens and incl parameters, or neither" if has_lens != has_incl
+ self.fail "You must specify both the lens and incl parameters, or neither." if has_lens != has_incl
end
- # This is the acutal meat of the code. It forces
+ # This is the actual meat of the code. It forces
# augeas to be run and fails or not based on the augeas return
# code.
newproperty(:returns) do |property|
include Puppet::Util
- desc "The expected return code from the augeas command. Should not be set"
+ desc "The expected return code from the augeas command. Should not be set."
defaultto 0
# Make output a bit prettier
def change_to_s(currentvalue, newvalue)
"executed successfully"
end
# if the onlyif resource is provided, then the value is parsed.
# a return value of 0 will stop exection because it matches the
# default value.
def retrieve
if @resource.provider.need_to_run?()
:need_to_run
else
0
end
end
# Actually execute the command.
def sync
@resource.provider.execute_changes
end
end
end
diff --git a/lib/puppet/type/computer.rb b/lib/puppet/type/computer.rb
index 7a2c52d53..5f42a6a9b 100644
--- a/lib/puppet/type/computer.rb
+++ b/lib/puppet/type/computer.rb
@@ -1,66 +1,66 @@
Puppet::Type.newtype(:computer) do
@doc = "Computer object management using DirectoryService
on OS X.
Note that these are distinctly different kinds of objects to 'hosts',
as they require a MAC address and can have all sorts of policy attached to
them.
This provider only manages Computer objects in the local directory service
domain, not in remote directories.
If you wish to manage `/etc/hosts` file on Mac OS X, then simply use the host
type as per other platforms.
This type primarily exists to create localhost Computer objects that MCX
policy can then be attached to.
-
+
**Autorequires:** If Puppet is managing the plist file representing a
Computer object (located at `/var/db/dslocal/nodes/Default/computers/{name}.plist`),
the Computer resource will autorequire it."
# ensurable
# We autorequire the computer object in case it is being managed at the
# file level by Puppet.
autorequire(:file) do
if self[:name]
"/var/db/dslocal/nodes/Default/computers/#{self[:name]}.plist"
else
nil
end
end
newproperty(:ensure, :parent => Puppet::Property::Ensure) do
desc "Control the existences of this computer record. Set this attribute to
`present` to ensure the computer record exists. Set it to `absent`
to delete any computer records with this name"
newvalue(:present) do
provider.create
end
newvalue(:absent) do
provider.delete
end
end
newparam(:name) do
desc "The authoritative 'short' name of the computer record."
isnamevar
end
newparam(:realname) do
desc "The 'long' name of the computer record."
end
newproperty(:en_address) do
desc "The MAC address of the primary network interface. Must match en0."
end
newproperty(:ip_address) do
desc "The IP Address of the Computer object."
end
end
diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb
index 6e9caa75b..0f517996b 100755
--- a/lib/puppet/type/cron.rb
+++ b/lib/puppet/type/cron.rb
@@ -1,413 +1,413 @@
require 'etc'
require 'facter'
require 'puppet/util/filetype'
Puppet::Type.newtype(:cron) do
@doc = <<-EOT
Installs and manages cron jobs. Every cron resource requires a command
and user attribute, as well as at least one periodic attribute (hour,
minute, month, monthday, weekday, or special). While the name of the cron
job is not part of the actual job, it is used by Puppet to store and
retrieve it.
If you specify a cron job that matches an existing job in every way
except name, then the jobs will be considered equivalent and the
new name will be permanently associated with that job. Once this
association is made and synced to disk, you can then manage the job
normally (e.g., change the schedule of the job).
Example:
cron { logrotate:
command => "/usr/sbin/logrotate",
- user => root,
- hour => 2,
- minute => 0
+ user => root,
+ hour => 2,
+ minute => 0
}
Note that all periodic attributes can be specified as an array of values:
cron { logrotate:
command => "/usr/sbin/logrotate",
- user => root,
- hour => [2, 4]
+ user => root,
+ hour => [2, 4]
}
...or using ranges or the step syntax `*/2` (although there's no guarantee
that your `cron` daemon supports these):
cron { logrotate:
command => "/usr/sbin/logrotate",
- user => root,
- hour => ['2-4'],
- minute => '*/10'
+ user => root,
+ hour => ['2-4'],
+ minute => '*/10'
}
EOT
ensurable
# A base class for all of the Cron parameters, since they all have
# similar argument checking going on.
class CronParam < Puppet::Property
class << self
attr_accessor :boundaries, :default
end
# We have to override the parent method, because we consume the entire
# "should" array
def insync?(is)
self.is_to_s(is) == self.should_to_s
end
# A method used to do parameter input handling. Converts integers
# in string form to actual integers, and returns the value if it's
# an integer or false if it's just a normal string.
def numfix(num)
if num =~ /^\d+$/
return num.to_i
elsif num.is_a?(Integer)
return num
else
return false
end
end
# Verify that a number is within the specified limits. Return the
# number if it is, or false if it is not.
def limitcheck(num, lower, upper)
(num >= lower and num <= upper) && num
end
# Verify that a value falls within the specified array. Does case
# insensitive matching, and supports matching either the entire word
# or the first three letters of the word.
def alphacheck(value, ary)
tmp = value.downcase
# If they specified a shortened version of the name, then see
# if we can lengthen it (e.g., mon => monday).
if tmp.length == 3
ary.each_with_index { |name, index|
if name =~ /#{tmp}/i
return index
end
}
else
return ary.index(tmp) if ary.include?(tmp)
end
false
end
def should_to_s(newvalue = @should)
if newvalue
newvalue = [newvalue] unless newvalue.is_a?(Array)
if self.name == :command or newvalue[0].is_a? Symbol
newvalue[0]
else
newvalue.join(",")
end
else
nil
end
end
def is_to_s(currentvalue = @is)
if currentvalue
return currentvalue unless currentvalue.is_a?(Array)
if self.name == :command or currentvalue[0].is_a? Symbol
currentvalue[0]
else
currentvalue.join(",")
end
else
nil
end
end
def should
if @should and @should[0] == :absent
:absent
else
@should
end
end
def should=(ary)
super
@should.flatten!
end
# The method that does all of the actual parameter value
# checking; called by all of the +param<name>=+ methods.
# Requires the value, type, and bounds, and optionally supports
# a boolean of whether to do alpha checking, and if so requires
# the ary against which to do the checking.
munge do |value|
# Support 'absent' as a value, so that they can remove
# a value
if value == "absent" or value == :absent
return :absent
end
# Allow the */2 syntax
if value =~ /^\*\/[0-9]+$/
return value
end
# Allow ranges
if value =~ /^[0-9]+-[0-9]+$/
return value
end
# Allow ranges + */2
if value =~ /^[0-9]+-[0-9]+\/[0-9]+$/
return value
end
if value == "*"
return :absent
end
return value unless self.class.boundaries
lower, upper = self.class.boundaries
retval = nil
if num = numfix(value)
retval = limitcheck(num, lower, upper)
elsif respond_to?(:alpha)
# If it has an alpha method defined, then we check
# to see if our value is in that list and if so we turn
# it into a number
retval = alphacheck(value, alpha)
end
if retval
return retval.to_s
else
self.fail "#{value} is not a valid #{self.class.name}"
end
end
end
# Somewhat uniquely, this property does not actually change anything -- it
# just calls +@resource.sync+, which writes out the whole cron tab for
# the user in question. There is no real way to change individual cron
# jobs without rewriting the entire cron file.
#
# Note that this means that managing many cron jobs for a given user
# could currently result in multiple write sessions for that user.
newproperty(:command, :parent => CronParam) do
desc "The command to execute in the cron job. The environment
provided to the command varies by local system rules, and it is
best to always provide a fully qualified command. The user's
profile is not sourced when the command is run, so if the
user's environment is desired it should be sourced manually.
All cron parameters support `absent` as a value; this will
remove any existing values for that field."
def retrieve
return_value = super
return_value = return_value[0] if return_value && return_value.is_a?(Array)
return_value
end
def should
if @should
if @should.is_a? Array
@should[0]
else
devfail "command is not an array"
end
else
nil
end
end
end
newproperty(:special) do
desc "A special value such as 'reboot' or 'annually'.
Only available on supported systems such as Vixie Cron.
Overrides more specific time of day/week settings."
def specials
%w{reboot yearly annually monthly weekly daily midnight hourly}
end
validate do |value|
raise ArgumentError, "Invalid special schedule #{value.inspect}" unless specials.include?(value)
end
end
newproperty(:minute, :parent => CronParam) do
self.boundaries = [0, 59]
desc "The minute at which to run the cron job.
Optional; if specified, must be between 0 and 59, inclusive."
end
newproperty(:hour, :parent => CronParam) do
self.boundaries = [0, 23]
desc "The hour at which to run the cron job. Optional;
if specified, must be between 0 and 23, inclusive."
end
newproperty(:weekday, :parent => CronParam) do
def alpha
%w{sunday monday tuesday wednesday thursday friday saturday}
end
self.boundaries = [0, 7]
desc "The weekday on which to run the command.
Optional; if specified, must be between 0 and 7, inclusive, with
0 (or 7) being Sunday, or must be the name of the day (e.g., Tuesday)."
end
newproperty(:month, :parent => CronParam) do
def alpha
%w{january february march april may june july
august september october november december}
end
self.boundaries = [1, 12]
desc "The month of the year. Optional; if specified
must be between 1 and 12 or the month name (e.g., December)."
end
newproperty(:monthday, :parent => CronParam) do
self.boundaries = [1, 31]
desc "The day of the month on which to run the
command. Optional; if specified, must be between 1 and 31."
end
newproperty(:environment) do
desc "Any environment settings associated with this cron job. They
will be stored between the header and the job in the crontab. There
can be no guarantees that other, earlier settings will not also
affect a given cron job.
Also, Puppet cannot automatically determine whether an existing,
unmanaged environment setting is associated with a given cron
job. If you already have cron jobs with environment settings,
then Puppet will keep those settings in the same place in the file,
but will not associate them with a specific job.
Settings should be specified exactly as they should appear in
the crontab, e.g., `PATH=/bin:/usr/bin:/usr/sbin`."
validate do |value|
unless value =~ /^\s*(\w+)\s*=\s*(.*)\s*$/ or value == :absent or value == "absent"
raise ArgumentError, "Invalid environment setting #{value.inspect}"
end
end
def insync?(is)
if is.is_a? Array
return is.sort == @should.sort
else
return is == @should
end
end
def is_to_s(newvalue)
if newvalue
if newvalue.is_a?(Array)
newvalue.join(",")
else
newvalue
end
else
nil
end
end
def should
@should
end
def should_to_s(newvalue = @should)
if newvalue
newvalue.join(",")
else
nil
end
end
end
newparam(:name) do
desc "The symbolic name of the cron job. This name
is used for human reference only and is generated automatically
for cron jobs found on the system. This generally won't
matter, as Puppet will do its best to match existing cron jobs
- against specified jobs (and Puppet adds a comment to cron jobs it adds), but it is at least possible that converting from
- unmanaged jobs to managed jobs might require manual
- intervention."
+ against specified jobs (and Puppet adds a comment to cron jobs it adds),
+ but it is at least possible that converting from unmanaged jobs to
+ managed jobs might require manual intervention."
isnamevar
end
newproperty(:user) do
desc "The user to run the command as. This user must
be allowed to run cron jobs, which is not currently checked by
Puppet.
The user defaults to whomever Puppet is running as."
defaultto { Etc.getpwuid(Process.uid).name || "root" }
end
newproperty(:target) do
desc "Where the cron job should be stored. For crontab-style
entries this is the same as the user and defaults that way.
Other providers default accordingly."
defaultto {
if provider.is_a?(@resource.class.provider(:crontab))
if val = @resource.should(:user)
val
else
raise ArgumentError,
"You must provide a user with crontab entries"
end
elsif provider.class.ancestors.include?(Puppet::Provider::ParsedFile)
provider.class.default_target
else
nil
end
}
end
# We have to reorder things so that :provide is before :target
attr_accessor :uid
def value(name)
name = symbolize(name)
ret = nil
if obj = @parameters[name]
ret = obj.should
ret ||= obj.retrieve
if ret == :absent
ret = nil
end
end
unless ret
case name
when :command
devfail "No command, somehow" unless @parameters[:ensure].value == :absent
when :special
# nothing
else
#ret = (self.class.validproperty?(name).default || "*").to_s
ret = "*"
end
end
ret
end
end
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 7c962ab4e..ec497630d 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -1,505 +1,512 @@
module Puppet
newtype(:exec) do
include Puppet::Util::Execution
require 'timeout'
@doc = "Executes external commands. It is critical that all commands
executed using this mechanism can be run multiple times without
harm, i.e., they are *idempotent*. One useful way to create idempotent
commands is to use the checks like `creates` to avoid running the
command unless some condition is met.
Note that you can restrict an `exec` to only run when it receives
events by using the `refreshonly` parameter; this is a useful way to
have your configuration respond to events with arbitrary commands.
Note also that if an `exec` receives an event from another resource,
it will get executed again (or execute the command specified in `refresh`, if there is one).
There is a strong tendency to use `exec` to do whatever work Puppet
can't already do; while this is obviously acceptable (and unavoidable)
in the short term, it is highly recommended to migrate work from `exec`
to native Puppet types as quickly as possible. If you find that
you are doing a lot of work with `exec`, please at least notify
us at Puppet Labs what you are doing, and hopefully we can work with
you to get a native resource type for the work you are doing.
- **Autorequires:** If Puppet is managing an exec's cwd or the executable file used in an exec's command, the exec resource will autorequire those files. If Puppet is managing the user that an exec should run as, the exec resource will autorequire that user."
+ **Autorequires:** If Puppet is managing an exec's cwd or the executable
+ file used in an exec's command, the exec resource will autorequire those
+ files. If Puppet is managing the user that an exec should run as, the
+ exec resource will autorequire that user."
# Create a new check mechanism. It's basically just a parameter that
# provides one extra 'check' method.
def self.newcheck(name, options = {}, &block)
@checks ||= {}
check = newparam(name, options, &block)
@checks[name] = check
end
def self.checks
@checks.keys
end
newproperty(:returns, :array_matching => :all, :event => :executed_command) do |property|
include Puppet::Util::Execution
munge do |value|
value.to_s
end
def event_name
:executed_command
end
defaultto "0"
attr_reader :output
desc "The expected return code(s). An error will be returned if the
executed command returns something else. Defaults to 0. Can be
specified as an array of acceptable return codes or a single value."
# Make output a bit prettier
def change_to_s(currentvalue, newvalue)
"executed successfully"
end
# First verify that all of our checks pass.
def retrieve
# We need to return :notrun to trigger evaluation; when that isn't
# true, we *LIE* about what happened and return a "success" for the
# value, which causes us to be treated as in_sync?, which means we
# don't actually execute anything. I think. --daniel 2011-03-10
if @resource.check_all_attributes
return :notrun
else
return self.should
end
end
# Actually execute the command.
def sync
olddir = nil
# We need a dir to change to, even if it's just the cwd
dir = self.resource[:cwd] || Dir.pwd
event = :executed_command
tries = self.resource[:tries]
try_sleep = self.resource[:try_sleep]
begin
tries.times do |try|
# Only add debug messages for tries > 1 to reduce log spam.
debug("Exec try #{try+1}/#{tries}") if tries > 1
@output, @status = provider.run(self.resource[:command])
break if self.should.include?(@status.exitstatus.to_s)
if try_sleep > 0 and tries > 1
debug("Sleeping for #{try_sleep} seconds between tries")
sleep try_sleep
end
end
rescue Timeout::Error
self.fail "Command exceeded timeout" % value.inspect
end
if log = @resource[:logoutput]
case log
when :true
log = @resource[:loglevel]
when :on_failure
unless self.should.include?(@status.exitstatus.to_s)
log = @resource[:loglevel]
else
log = :false
end
end
unless log == :false
@output.split(/\n/).each { |line|
self.send(log, line)
}
end
end
unless self.should.include?(@status.exitstatus.to_s)
self.fail("#{self.resource[:command]} returned #{@status.exitstatus} instead of one of [#{self.should.join(",")}]")
end
event
end
end
newparam(:command) do
isnamevar
desc "The actual command to execute. Must either be fully qualified
or a search path for the command must be provided. If the command
succeeds, any output produced will be logged at the instance's
normal log level (usually `notice`), but if the command fails
(meaning its return code does not match the specified code) then
any output is logged at the `err` log level."
end
newparam(:path) do
desc "The search path used for command execution.
Commands must be fully qualified if no path is specified. Paths
can be specified as an array or as a '#{File::PATH_SEPARATOR}' separated list."
# Support both arrays and colon-separated fields.
def value=(*values)
@value = values.flatten.collect { |val|
val.split(File::PATH_SEPARATOR)
}.flatten
end
end
newparam(:user) do
desc "The user to run the command as. Note that if you
use this then any error output is not currently captured. This
is because of a bug within Ruby. If you are using Puppet to
create this user, the exec will automatically require the user,
as long as it is specified by name."
# Most validation is handled by the SUIDManager class.
validate do |user|
self.fail "Only root can execute commands as other users" unless Puppet.features.root?
self.fail "Unable to execute commands as other users on Windows" if Puppet.features.microsoft_windows?
end
end
newparam(:group) do
desc "The group to run the command as. This seems to work quite
haphazardly on different platforms -- it is a platform issue
not a Ruby or Puppet one, since the same variety exists when
running commnands as different users in the shell."
# Validation is handled by the SUIDManager class.
end
newparam(:cwd, :parent => Puppet::Parameter::Path) do
desc "The directory from which to run the command. If
this directory does not exist, the command will fail."
end
newparam(:logoutput) do
desc "Whether to log output. Defaults to logging output at the
loglevel for the `exec` resource. Use *on_failure* to only
log the output when the command reports an error. Values are
**true**, *false*, *on_failure*, and any legal log level."
newvalues(:true, :false, :on_failure)
end
newparam(:refresh) do
desc "How to refresh this command. By default, the exec is just
called again when it receives an event from another resource,
but this parameter allows you to define a different command
for refreshing."
validate do |command|
provider.validatecmd(command)
end
end
newparam(:environment) do
desc "Any additional environment variables you want to set for a
command. Note that if you use this to set PATH, it will override
the `path` attribute. Multiple environment variables should be
specified as an array."
validate do |values|
values = [values] unless values.is_a? Array
values.each do |value|
unless value =~ /\w+=/
raise ArgumentError, "Invalid environment setting '#{value}'"
end
end
end
end
newparam(:timeout) do
desc "The maximum time the command should take. If the command takes
longer than the timeout, the command is considered to have failed
and will be stopped. Use 0 to disable the timeout.
The time is specified in seconds."
munge do |value|
value = value.shift if value.is_a?(Array)
begin
value = Float(value)
rescue ArgumentError => e
raise ArgumentError, "The timeout must be a number."
end
[value, 0.0].max
end
defaultto 300
end
newparam(:tries) do
desc "The number of times execution of the command should be tried.
Defaults to '1'. This many attempts will be made to execute
the command until an acceptable return code is returned.
Note that the timeout paramater applies to each try rather than
to the complete set of tries."
munge do |value|
if value.is_a?(String)
unless value =~ /^[\d]+$/
raise ArgumentError, "Tries must be an integer"
end
value = Integer(value)
end
raise ArgumentError, "Tries must be an integer >= 1" if value < 1
value
end
defaultto 1
end
newparam(:try_sleep) do
desc "The time to sleep in seconds between 'tries'."
munge do |value|
if value.is_a?(String)
unless value =~ /^[-\d.]+$/
raise ArgumentError, "try_sleep must be a number"
end
value = Float(value)
end
raise ArgumentError, "try_sleep cannot be a negative number" if value < 0
value
end
defaultto 0
end
newcheck(:refreshonly) do
- desc "The command should only be run as a
+ desc <<-EOT
+ The command should only be run as a
refresh mechanism for when a dependent object is changed. It only
makes sense to use this option when this command depends on some
other object; it is useful for triggering an action:
# Pull down the main aliases file
- file { \"/etc/aliases\":
- source => \"puppet://server/module/aliases\"
+ file { "/etc/aliases":
+ source => "puppet://server/module/aliases"
}
# Rebuild the database, but only when the file changes
exec { newaliases:
- path => [\"/usr/bin\", \"/usr/sbin\"],
- subscribe => File[\"/etc/aliases\"],
+ path => ["/usr/bin", "/usr/sbin"],
+ subscribe => File["/etc/aliases"],
refreshonly => true
}
Note that only `subscribe` and `notify` can trigger actions, not `require`,
- so it only makes sense to use `refreshonly` with `subscribe` or `notify`."
+ so it only makes sense to use `refreshonly` with `subscribe` or `notify`.
+ EOT
newvalues(:true, :false)
# We always fail this test, because we're only supposed to run
# on refresh.
def check(value)
# We have to invert the values.
if value == :true
false
else
true
end
end
end
newcheck(:creates, :parent => Puppet::Parameter::Path) do
desc <<-EOT
A file that this command creates. If this
parameter is provided, then the command will only be run
if the specified file does not exist.
exec { "tar -xf /Volumes/nfs02/important.tar":
- cwd => "/var/tmp",
+ cwd => "/var/tmp",
creates => "/var/tmp/myfile",
- path => ["/usr/bin", "/usr/sbin"]
+ path => ["/usr/bin", "/usr/sbin"]
}
In this example, if `/var/tmp/myfile` is ever deleted, the exec
will bring it back by re-extracting the tarball.
EOT
accept_arrays
# If the file exists, return false (i.e., don't run the command),
# else return true
def check(value)
! FileTest.exists?(value)
end
end
newcheck(:unless) do
- desc "If this parameter is set, then this `exec` will run unless
+ desc <<-EOT
+ If this parameter is set, then this `exec` will run unless
the command returns 0. For example:
- exec { \"/bin/echo root >> /usr/lib/cron/cron.allow\":
- path => \"/usr/bin:/usr/sbin:/bin\",
- unless => \"grep root /usr/lib/cron/cron.allow 2>/dev/null\"
+ exec { "/bin/echo root >> /usr/lib/cron/cron.allow":
+ path => "/usr/bin:/usr/sbin:/bin",
+ unless => "grep root /usr/lib/cron/cron.allow 2>/dev/null"
}
This would add `root` to the cron.allow file (on Solaris) unless
`grep` determines it's already there.
Note that this command follows the same rules as the main command,
which is to say that it must be fully qualified if the path is not set.
- "
+ EOT
validate do |cmds|
cmds = [cmds] unless cmds.is_a? Array
cmds.each do |command|
provider.validatecmd(command)
end
end
# Return true if the command does not return 0.
def check(value)
begin
output, status = provider.run(value, true)
rescue Timeout::Error
err "Check #{value.inspect} exceeded timeout"
return false
end
status.exitstatus != 0
end
end
newcheck(:onlyif) do
- desc "If this parameter is set, then this `exec` will only run if
+ desc <<-EOT
+ If this parameter is set, then this `exec` will only run if
the command returns 0. For example:
- exec { \"logrotate\":
- path => \"/usr/bin:/usr/sbin:/bin\",
- onlyif => \"test `du /var/log/messages | cut -f1` -gt 100000\"
+ exec { "logrotate":
+ path => "/usr/bin:/usr/sbin:/bin",
+ onlyif => "test `du /var/log/messages | cut -f1` -gt 100000"
}
This would run `logrotate` only if that test returned true.
Note that this command follows the same rules as the main command,
which is to say that it must be fully qualified if the path is not set.
Also note that onlyif can take an array as its value, e.g.:
- onlyif => [\"test -f /tmp/file1\", \"test -f /tmp/file2\"]
+ onlyif => ["test -f /tmp/file1", "test -f /tmp/file2"]
- This will only run the exec if /all/ conditions in the array return true.
- "
+ This will only run the exec if _all_ conditions in the array return true.
+ EOT
validate do |cmds|
cmds = [cmds] unless cmds.is_a? Array
cmds.each do |command|
provider.validatecmd(command)
end
end
# Return true if the command returns 0.
def check(value)
begin
output, status = provider.run(value, true)
rescue Timeout::Error
err "Check #{value.inspect} exceeded timeout"
return false
end
status.exitstatus == 0
end
end
# Exec names are not isomorphic with the objects.
@isomorphic = false
validate do
provider.validatecmd(self[:command])
end
# FIXME exec should autorequire any exec that 'creates' our cwd
autorequire(:file) do
reqs = []
# Stick the cwd in there if we have it
reqs << self[:cwd] if self[:cwd]
file_regex = Puppet.features.microsoft_windows? ? %r{^([a-zA-Z]:[\\/]\S+)} : %r{^(/\S+)}
self[:command].scan(file_regex) { |str|
reqs << str
}
self[:command].scan(/^"([^"]+)"/) { |str|
reqs << str
}
[:onlyif, :unless].each { |param|
next unless tmp = self[param]
tmp = [tmp] unless tmp.is_a? Array
tmp.each do |line|
# And search the command line for files, adding any we
# find. This will also catch the command itself if it's
# fully qualified. It might not be a bad idea to add
# unqualified files, but, well, that's a bit more annoying
# to do.
reqs += line.scan(file_regex)
end
}
# For some reason, the += isn't causing a flattening
reqs.flatten!
reqs
end
autorequire(:user) do
# Autorequire users if they are specified by name
if user = self[:user] and user !~ /^\d+$/
user
end
end
def self.instances
[]
end
# Verify that we pass all of the checks. The argument determines whether
# we skip the :refreshonly check, which is necessary because we now check
# within refresh
def check_all_attributes(refreshing = false)
self.class.checks.each { |check|
next if refreshing and check == :refreshonly
if @parameters.include?(check)
val = @parameters[check].value
val = [val] unless val.is_a? Array
val.each do |value|
return false unless @parameters[check].check(value)
end
end
}
true
end
def output
if self.property(:returns).nil?
return nil
else
return self.property(:returns).output
end
end
# Run the command, or optionally run a separately-specified command.
def refresh
if self.check_all_attributes(true)
if cmd = self[:refresh]
provider.run(cmd)
else
self.property(:returns).sync
end
end
end
end
end
diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index bfe61144d..0de6fde08 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -1,803 +1,804 @@
require 'digest/md5'
require 'cgi'
require 'etc'
require 'uri'
require 'fileutils'
require 'enumerator'
require 'pathname'
require 'puppet/network/handler'
require 'puppet/util/diff'
require 'puppet/util/checksums'
-require 'puppet/network/client'
require 'puppet/util/backups'
Puppet::Type.newtype(:file) do
include Puppet::Util::MethodHelper
include Puppet::Util::Checksums
include Puppet::Util::Backups
@doc = "Manages local files, including setting ownership and
permissions, creation of both files and directories, and
retrieving entire files from remote servers. As Puppet matures, it
expected that the `file` resource will be used less and less to
manage content, and instead native resources will be used to do so.
If you find that you are often copying files in from a central
location, rather than using native resources, please contact
Puppet Labs and we can hopefully work with you to develop a
native resource to support what you are doing.
- **Autorequires:** If Puppet is managing the user or group that owns a file, the file resource will autorequire them. If Puppet is managing any parent directories of a file, the file resource will autorequire them."
+ **Autorequires:** If Puppet is managing the user or group that owns a
+ file, the file resource will autorequire them. If Puppet is managing any
+ parent directories of a file, the file resource will autorequire them."
def self.title_patterns
[ [ /^(.*?)\/*\Z/m, [ [ :path, lambda{|x| x} ] ] ] ]
end
newparam(:path) do
desc "The path to the file to manage. Must be fully qualified."
isnamevar
validate do |value|
unless Puppet::Util.absolute_path?(value)
fail Puppet::Error, "File paths must be fully qualified, not '#{value}'"
end
end
# convert the current path in an index into the collection and the last
# path name. The aim is to use less storage for all common paths in a hierarchy
munge do |value|
# We know the value is absolute, so expanding it will just standardize it.
path, name = ::File.split(::File.expand_path value)
{ :index => Puppet::FileCollection.collection.index(path), :name => name }
end
# and the reverse
unmunge do |value|
basedir = Puppet::FileCollection.collection.path(value[:index])
::File.expand_path ::File.join( basedir, value[:name] )
end
end
newparam(:backup) do
desc "Whether files should be backed up before
being replaced. The preferred method of backing files up is via
a `filebucket`, which stores files by their MD5 sums and allows
easy retrieval without littering directories with backups. You
can specify a local filebucket or a network-accessible
server-based filebucket by setting `backup => bucket-name`.
Alternatively, if you specify any value that begins with a `.`
(e.g., `.puppet-bak`), then Puppet will use copy the file in
the same directory with that value as the extension of the
backup. Setting `backup => false` disables all backups of the
file in question.
Puppet automatically creates a local filebucket named `puppet` and
defaults to backing up there. To use a server-based filebucket,
you must specify one in your configuration.
filebucket { main:
server => puppet,
path => false,
# The path => false line works around a known issue with the filebucket type.
}
The `puppet master` daemon creates a filebucket by default,
so you can usually back up to your main server with this
configuration. Once you've described the bucket in your
configuration, you can use it in any file's backup attribute:
file { \"/my/file\":
source => \"/path/in/nfs/or/something\",
backup => main
}
This will back the file up to the central server.
At this point, the benefits of using a central filebucket are that you
do not have backup files lying around on each of your machines, a given
version of a file is only backed up once, you can restore any given file
manually (no matter how old), and you can use Puppet Dashboard to view
file contents. Eventually, transactional support will be able to
automatically restore filebucketed files.
"
defaultto "puppet"
munge do |value|
# I don't really know how this is happening.
value = value.shift if value.is_a?(Array)
case value
when false, "false", :false
false
when true, "true", ".puppet-bak", :true
".puppet-bak"
when String
value
else
self.fail "Invalid backup type #{value.inspect}"
end
end
end
newparam(:recurse) do
desc "Whether and how deeply to do recursive
management. Options are:
* `inf,true` --- Regular style recursion on both remote and local
directory structure.
* `remote` --- Descends recursively into the remote directory
but not the local directory. Allows copying of
a few files into a directory containing many
unmanaged files without scanning all the local files.
* `false` --- Default of no recursion.
* `[0-9]+` --- Same as true, but limit recursion. Warning: this syntax
has been deprecated in favor of the `recurselimit` attribute.
"
newvalues(:true, :false, :inf, :remote, /^[0-9]+$/)
# Replace the validation so that we allow numbers in
# addition to string representations of them.
validate { |arg| }
munge do |value|
newval = super(value)
case newval
when :true, :inf; true
when :false; false
when :remote; :remote
when Integer, Fixnum, Bignum
self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit"
# recurse == 0 means no recursion
return false if value == 0
resource[:recurselimit] = value
true
when /^\d+$/
self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit"
value = Integer(value)
# recurse == 0 means no recursion
return false if value == 0
resource[:recurselimit] = value
true
else
self.fail "Invalid recurse value #{value.inspect}"
end
end
end
newparam(:recurselimit) do
desc "How deeply to do recursive management."
newvalues(/^[0-9]+$/)
munge do |value|
newval = super(value)
case newval
when Integer, Fixnum, Bignum; value
when /^\d+$/; Integer(value)
else
self.fail "Invalid recurselimit value #{value.inspect}"
end
end
end
newparam(:replace, :boolean => true) do
desc "Whether or not to replace a file that is
sourced but exists. This is useful for using file sources
purely for initialization."
newvalues(:true, :false)
aliasvalue(:yes, :true)
aliasvalue(:no, :false)
defaultto :true
end
newparam(:force, :boolean => true) do
desc "Force the file operation. Currently only used when replacing
directories with links."
newvalues(:true, :false)
defaultto false
end
newparam(:ignore) do
desc "A parameter which omits action on files matching
specified patterns during recursion. Uses Ruby's builtin globbing
engine, so shell metacharacters are fully supported, e.g. `[a-z]*`.
Matches that would descend into the directory structure are ignored,
e.g., `*/*`."
validate do |value|
unless value.is_a?(Array) or value.is_a?(String) or value == false
self.devfail "Ignore must be a string or an Array"
end
end
end
newparam(:links) do
desc "How to handle links during file actions. During file copying,
`follow` will copy the target file instead of the link, `manage`
will copy the link itself, and `ignore` will just pass it by.
When not copying, `manage` and `ignore` behave equivalently
- (because you cannot really ignore links entirely during local recursion), and `follow` will manage the file to which the
- link points."
+ (because you cannot really ignore links entirely during local
+ recursion), and `follow` will manage the file to which the link points."
newvalues(:follow, :manage)
defaultto :manage
end
newparam(:purge, :boolean => true) do
desc "Whether unmanaged files should be purged. If you have a filebucket
configured the purged files will be uploaded, but if you do not,
this will destroy data. Only use this option for generated
files unless you really know what you are doing. This option only
makes sense when recursively managing directories.
Note that when using `purge` with `source`, Puppet will purge any files
that are not on the remote system."
defaultto :false
newvalues(:true, :false)
end
newparam(:sourceselect) do
desc "Whether to copy all valid sources, or just the first one. This parameter
is only used in recursive copies; by default, the first valid source is the
only one used as a recursive source, but if this parameter is set to `all`,
then all valid sources will have all of their contents copied to the local host,
and for sources that have the same file, the source earlier in the list will
be used."
defaultto :first
newvalues(:first, :all)
end
# Autorequire the nearest ancestor directory found in the catalog.
autorequire(:file) do
path = Pathname(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
end
end
# Autorequire the owner and group of the file.
{:user => :owner, :group => :group}.each do |type, property|
autorequire(type) do
if @parameters.include?(property)
# The user/group property automatically converts to IDs
next unless should = @parameters[property].shouldorig
val = should[0]
if val.is_a?(Integer) or val =~ /^\d+$/
nil
else
val
end
end
end
end
CREATORS = [:content, :source, :target]
SOURCE_ONLY_CHECKSUMS = [:none, :ctime, :mtime]
validate do
creator_count = 0
CREATORS.each do |param|
creator_count += 1 if self.should(param)
end
creator_count += 1 if @parameters.include?(:source)
self.fail "You cannot specify more than one of #{CREATORS.collect { |p| p.to_s}.join(", ")}" if creator_count > 1
self.fail "You cannot specify a remote recursion without a source" if !self[:source] and self[:recurse] == :remote
self.fail "You cannot specify source when using checksum 'none'" if self[:checksum] == :none && !self[:source].nil?
SOURCE_ONLY_CHECKSUMS.each do |checksum_type|
self.fail "You cannot specify content when using checksum '#{checksum_type}'" if self[:checksum] == checksum_type && !self[:content].nil?
end
self.warning "Possible error: recurselimit is set but not recurse, no recursion will happen" if !self[:recurse] and self[:recurselimit]
end
def self.[](path)
return nil unless path
super(path.gsub(/\/+/, '/').sub(/\/$/, ''))
end
def self.instances
return []
end
# Determine the user to write files as.
def asuser
if self.should(:owner) and ! self.should(:owner).is_a?(Symbol)
writeable = Puppet::Util::SUIDManager.asuser(self.should(:owner)) {
FileTest.writable?(::File.dirname(self[:path]))
}
# If the parent directory is writeable, then we execute
# as the user in question. Otherwise we'll rely on
# the 'owner' property to do things.
asuser = self.should(:owner) if writeable
end
asuser
end
def bucket
return @bucket if @bucket
backup = self[:backup]
return nil unless backup
return nil if backup =~ /^\./
unless catalog or backup == "puppet"
fail "Can not find filebucket for backups without a catalog"
end
unless catalog and filebucket = catalog.resource(:filebucket, backup) or backup == "puppet"
fail "Could not find filebucket #{backup} specified in backup"
end
return default_bucket unless filebucket
@bucket = filebucket.bucket
@bucket
end
def default_bucket
Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
end
# Does the file currently exist? Just checks for whether
# we have a stat
def exist?
stat ? true : false
end
# We have to do some extra finishing, to retrieve our bucket if
# there is one.
def finish
# Look up our bucket, if there is one
bucket
super
end
# Create any children via recursion or whatever.
def eval_generate
return [] unless self.recurse?
recurse
#recurse.reject do |resource|
# catalog.resource(:file, resource[:path])
#end.each do |child|
# catalog.add_resource child
# catalog.relationship_graph.add_edge self, child
#end
end
def flush
# We want to make sure we retrieve metadata anew on each transaction.
@parameters.each do |name, param|
param.flush if param.respond_to?(:flush)
end
@stat = :needs_stat
end
def initialize(hash)
# Used for caching clients
@clients = {}
super
# If they've specified a source, we get our 'should' values
# from it.
unless self[:ensure]
if self[:target]
self[:ensure] = :symlink
elsif self[:content]
self[:ensure] = :file
end
end
@stat = :needs_stat
end
# Configure discovered resources to be purged.
def mark_children_for_purging(children)
children.each do |name, child|
next if child[:source]
child[:ensure] = :absent
end
end
# Create a new file or directory object as a child to the current
# object.
def newchild(path)
full_path = ::File.join(self[:path], path)
# Add some new values to our original arguments -- these are the ones
# set at initialization. We specifically want to exclude any param
# values set by the :source property or any default values.
# LAK:NOTE This is kind of silly, because the whole point here is that
# the values set at initialization should live as long as the resource
# but values set by default or by :source should only live for the transaction
# or so. Unfortunately, we don't have a straightforward way to manage
# the different lifetimes of this data, so we kludge it like this.
# The right-side hash wins in the merge.
options = @original_parameters.merge(:path => full_path).reject { |param, value| value.nil? }
# These should never be passed to our children.
[:parent, :ensure, :recurse, :recurselimit, :target, :alias, :source].each do |param|
options.delete(param) if options.include?(param)
end
self.class.new(options)
end
# Files handle paths specially, because they just lengthen their
# path names, rather than including the full parent's title each
# time.
def pathbuilder
# We specifically need to call the method here, so it looks
# up our parent in the catalog graph.
if parent = parent()
# We only need to behave specially when our parent is also
# a file
if parent.is_a?(self.class)
# Remove the parent file name
list = parent.pathbuilder
list.pop # remove the parent's path info
return list << self.ref
else
return super
end
else
return [self.ref]
end
end
# Should we be purging?
def purge?
@parameters.include?(:purge) and (self[:purge] == :true or self[:purge] == "true")
end
# Recursively generate a list of file resources, which will
# be used to copy remote files, manage local files, and/or make links
# to map to another directory.
def recurse
children = (self[:recurse] == :remote) ? {} : recurse_local
if self[:target]
recurse_link(children)
elsif self[:source]
recurse_remote(children)
end
# If we're purging resources, then delete any resource that isn't on the
# remote system.
mark_children_for_purging(children) if self.purge?
result = children.values.sort { |a, b| a[:path] <=> b[:path] }
remove_less_specific_files(result)
end
# This is to fix bug #2296, where two files recurse over the same
# set of files. It's a rare case, and when it does happen you're
# not likely to have many actual conflicts, which is good, because
# this is a pretty inefficient implementation.
def remove_less_specific_files(files)
mypath = self[:path].split(::File::Separator)
other_paths = catalog.vertices.
select { |r| r.is_a?(self.class) and r[:path] != self[:path] }.
collect { |r| r[:path].split(::File::Separator) }.
select { |p| p[0,mypath.length] == mypath }
return files if other_paths.empty?
files.reject { |file|
path = file[:path].split(::File::Separator)
other_paths.any? { |p| path[0,p.length] == p }
}
end
# A simple method for determining whether we should be recursing.
def recurse?
self[:recurse] == true or self[:recurse] == :remote
end
# Recurse the target of the link.
def recurse_link(children)
perform_recursion(self[:target]).each do |meta|
if meta.relative_path == "."
self[:ensure] = :directory
next
end
children[meta.relative_path] ||= newchild(meta.relative_path)
if meta.ftype == "directory"
children[meta.relative_path][:ensure] = :directory
else
children[meta.relative_path][:ensure] = :link
children[meta.relative_path][:target] = meta.full_path
end
end
children
end
# Recurse the file itself, returning a Metadata instance for every found file.
def recurse_local
result = perform_recursion(self[:path])
return {} unless result
result.inject({}) do |hash, meta|
next hash if meta.relative_path == "."
hash[meta.relative_path] = newchild(meta.relative_path)
hash
end
end
# Recurse against our remote file.
def recurse_remote(children)
sourceselect = self[:sourceselect]
total = self[:source].collect do |source|
next unless result = perform_recursion(source)
return if top = result.find { |r| r.relative_path == "." } and top.ftype != "directory"
result.each { |data| data.source = "#{source}/#{data.relative_path}" }
break result if result and ! result.empty? and sourceselect == :first
result
end.flatten
# This only happens if we have sourceselect == :all
unless sourceselect == :first
found = []
total.reject! do |data|
result = found.include?(data.relative_path)
found << data.relative_path unless found.include?(data.relative_path)
result
end
end
total.each do |meta|
if meta.relative_path == "."
parameter(:source).metadata = meta
next
end
children[meta.relative_path] ||= newchild(meta.relative_path)
children[meta.relative_path][:source] = meta.source
children[meta.relative_path][:checksum] = :md5 if meta.ftype == "file"
children[meta.relative_path].parameter(:source).metadata = meta
end
children
end
def perform_recursion(path)
Puppet::FileServing::Metadata.indirection.search(
path,
:links => self[:links],
:recurse => (self[:recurse] == :remote ? true : self[:recurse]),
:recurselimit => self[:recurselimit],
:ignore => self[:ignore],
:checksum_type => (self[:source] || self[:content]) ? self[:checksum] : :none
)
end
# Remove any existing data. This is only used when dealing with
# links or directories.
def remove_existing(should)
return unless s = stat
self.fail "Could not back up; will not replace" unless perform_backup
unless should.to_s == "link"
return if s.ftype.to_s == should.to_s
end
case s.ftype
when "directory"
if self[:force] == :true
debug "Removing existing directory for replacement with #{should}"
FileUtils.rmtree(self[:path])
else
notice "Not removing directory; use 'force' to override"
return
end
when "link", "file"
debug "Removing existing #{s.ftype} for replacement with #{should}"
::File.unlink(self[:path])
else
self.fail "Could not back up files of type #{s.ftype}"
end
@stat = :needs_stat
true
end
def retrieve
if source = parameter(:source)
source.copy_source_values
end
super
end
# Set the checksum, from another property. There are multiple
# properties that modify the contents of a file, and they need the
# ability to make sure that the checksum value is in sync.
def setchecksum(sum = nil)
if @parameters.include? :checksum
if sum
@parameters[:checksum].checksum = sum
else
# If they didn't pass in a sum, then tell checksum to
# figure it out.
currentvalue = @parameters[:checksum].retrieve
@parameters[:checksum].checksum = currentvalue
end
end
end
# Should this thing be a normal file? This is a relatively complex
# way of determining whether we're trying to create a normal file,
# and it's here so that the logic isn't visible in the content property.
def should_be_file?
return true if self[:ensure] == :file
# I.e., it's set to something like "directory"
return false if e = self[:ensure] and e != :present
# The user doesn't really care, apparently
if self[:ensure] == :present
return true unless s = stat
return(s.ftype == "file" ? true : false)
end
# If we've gotten here, then :ensure isn't set
return true if self[:content]
return true if stat and stat.ftype == "file"
false
end
# Stat our file. Depending on the value of the 'links' attribute, we
# use either 'stat' or 'lstat', and we expect the properties to use the
# resulting stat object accordingly (mostly by testing the 'ftype'
# value).
#
# We use the initial value :needs_stat to ensure we only stat the file once,
# but can also keep track of a failed stat (@stat == nil). This also allows
# us to re-stat on demand by setting @stat = :needs_stat.
def stat
return @stat unless @stat == :needs_stat
method = :stat
# Files are the only types that support links
if (self.class.name == :file and self[:links] != :follow) or self.class.name == :tidy
method = :lstat
end
@stat = begin
::File.send(method, self[:path])
rescue Errno::ENOENT => error
nil
rescue Errno::EACCES => error
warning "Could not stat; permission denied"
nil
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
end
# Write out the file. Requires the property name for logging.
# Write will be done by the content property, along with checksum computation
def write(property)
remove_existing(:file)
use_temporary_file = write_temporary_file?
if use_temporary_file
path = "#{self[:path]}.puppettmp_#{rand(10000)}"
path = "#{self[:path]}.puppettmp_#{rand(10000)}" while ::File.exists?(path) or ::File.symlink?(path)
else
path = self[:path]
end
mode = self.should(:mode) # might be nil
umask = mode ? 000 : 022
mode_int = mode ? mode.to_i(8) : nil
content_checksum = Puppet::Util.withumask(umask) { ::File.open(path, 'w', mode_int ) { |f| write_content(f) } }
# And put our new file in place
if use_temporary_file # This is only not true when our file is empty.
begin
fail_if_checksum_is_wrong(path, content_checksum) if validate_checksum?
::File.rename(path, self[:path])
rescue => detail
fail "Could not rename temporary file #{path} to #{self[:path]}: #{detail}"
ensure
# Make sure the created file gets removed
::File.unlink(path) if FileTest.exists?(path)
end
end
# make sure all of the modes are actually correct
property_fix
end
private
# Should we validate the checksum of the file we're writing?
def validate_checksum?
self[:checksum] !~ /time/
end
# Make sure the file we wrote out is what we think it is.
def fail_if_checksum_is_wrong(path, content_checksum)
newsum = parameter(:checksum).sum_file(path)
return if [:absent, nil, content_checksum].include?(newsum)
self.fail "File written to disk did not match checksum; discarding changes (#{content_checksum} vs #{newsum})"
end
# write the current content. Note that if there is no content property
# simply opening the file with 'w' as done in write is enough to truncate
# or write an empty length file.
def write_content(file)
(content = property(:content)) && content.write(file)
end
private
def write_temporary_file?
# unfortunately we don't know the source file size before fetching it
# so let's assume the file won't be empty
(c = property(:content) and c.length) || (s = @parameters[:source] and 1)
end
# There are some cases where all of the work does not get done on
# file creation/modification, so we have to do some extra checking.
def property_fix
properties.each do |thing|
next unless [:mode, :owner, :group, :seluser, :selrole, :seltype, :selrange].include?(thing.name)
# Make sure we get a new stat objct
@stat = :needs_stat
currentvalue = thing.retrieve
thing.sync unless thing.safe_insync?(currentvalue)
end
end
end
# We put all of the properties in separate files, because there are so many
# of them. The order these are loaded is important, because it determines
# the order they are in the property lit.
require 'puppet/type/file/checksum'
require 'puppet/type/file/content' # can create the file
require 'puppet/type/file/source' # can create the file
require 'puppet/type/file/target' # creates a different type of file
require 'puppet/type/file/ensure' # can create the file
require 'puppet/type/file/owner'
require 'puppet/type/file/group'
require 'puppet/type/file/mode'
require 'puppet/type/file/type'
require 'puppet/type/file/selcontext' # SELinux file context
require 'puppet/type/file/ctime'
require 'puppet/type/file/mtime'
diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb
index 0f065da14..a846856c8 100755
--- a/lib/puppet/type/file/ensure.rb
+++ b/lib/puppet/type/file/ensure.rb
@@ -1,164 +1,167 @@
module Puppet
Puppet::Type.type(:file).ensurable do
require 'etc'
- desc "Whether to create files that don't currently exist.
+ desc <<-EOT
+ Whether to create files that don't currently exist.
Possible values are *absent*, *present*, *file*, and *directory*.
Specifying `present` will match any form of file existence, and
if the file is missing will create an empty file. Specifying
- `absent` will delete the file (and directory if recurse => true).
+ `absent` will delete the file (and directory if `recurse => true`).
- Anything other than those values will create a symlink. In the interest of readability and clarity, you should use `ensure => link` and explicitly specify a
- target; however, if a `target` attribute isn't provided, the value of the `ensure`
- attribute will be used as the symlink target:
+ Anything other than those values will create a symlink. In the interest
+ of readability and clarity, you should use `ensure => link` and
+ explicitly specify a target; however, if a `target` attribute isn't
+ provided, the value of the `ensure` attribute will be used as the
+ symlink target. The following two declarations are equivalent:
# (Useful on Solaris)
- # Less maintainable:
- file { \"/etc/inetd.conf\":
- ensure => \"/etc/inet/inetd.conf\",
+
+ # Less maintainable:
+ file { "/etc/inetd.conf":
+ ensure => "/etc/inet/inetd.conf",
}
# More maintainable:
- file { \"/etc/inetd.conf\":
+ file { "/etc/inetd.conf":
ensure => link,
- target => \"/etc/inet/inetd.conf\",
+ target => "/etc/inet/inetd.conf",
}
-
- These two declarations are equivalent."
+ EOT
# Most 'ensure' properties have a default, but with files we, um, don't.
nodefault
newvalue(:absent) do
File.unlink(@resource[:path])
end
aliasvalue(:false, :absent)
newvalue(:file, :event => :file_created) do
# Make sure we're not managing the content some other way
if property = @resource.property(:content)
property.sync
else
@resource.write(:ensure)
mode = @resource.should(:mode)
end
end
#aliasvalue(:present, :file)
newvalue(:present, :event => :file_created) do
# Make a file if they want something, but this will match almost
# anything.
set_file
end
newvalue(:directory, :event => :directory_created) do
mode = @resource.should(:mode)
parent = File.dirname(@resource[:path])
unless FileTest.exists? parent
raise Puppet::Error,
"Cannot create #{@resource[:path]}; parent directory #{parent} does not exist"
end
if mode
Puppet::Util.withumask(000) do
Dir.mkdir(@resource[:path], mode.to_i(8))
end
else
Dir.mkdir(@resource[:path])
end
@resource.send(:property_fix)
return :directory_created
end
newvalue(:link, :event => :link_created) do
fail "Cannot create a symlink without a target" unless property = resource.property(:target)
property.retrieve
property.mklink
end
# Symlinks.
newvalue(/./) do
# This code never gets executed. We need the regex to support
# specifying it, but the work is done in the 'symlink' code block.
end
munge do |value|
value = super(value)
value,resource[:target] = :link,value unless value.is_a? Symbol
resource[:links] = :manage if value == :link and resource[:links] != :follow
value
end
def change_to_s(currentvalue, newvalue)
return super unless newvalue.to_s == "file"
return super unless property = @resource.property(:content)
# We know that content is out of sync if we're here, because
# it's essentially equivalent to 'ensure' in the transaction.
if source = @resource.parameter(:source)
should = source.checksum
else
should = property.should
end
if should == :absent
is = property.retrieve
else
is = :absent
end
property.change_to_s(is, should)
end
# Check that we can actually create anything
def check
basedir = File.dirname(@resource[:path])
if ! FileTest.exists?(basedir)
raise Puppet::Error,
"Can not create #{@resource.title}; parent directory does not exist"
elsif ! FileTest.directory?(basedir)
raise Puppet::Error,
"Can not create #{@resource.title}; #{dirname} is not a directory"
end
end
# We have to treat :present specially, because it works with any
# type of file.
def insync?(currentvalue)
unless currentvalue == :absent or resource.replace?
return true
end
if self.should == :present
return !(currentvalue.nil? or currentvalue == :absent)
else
return super(currentvalue)
end
end
def retrieve
if stat = @resource.stat
return stat.ftype.intern
else
if self.should == :false
return :false
else
return :absent
end
end
end
def sync
@resource.remove_existing(self.should)
if self.should == :absent
return :file_removed
end
event = super
event
end
end
end
diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb
index 7dd2174c8..da1e5815c 100755
--- a/lib/puppet/type/file/mode.rb
+++ b/lib/puppet/type/file/mode.rb
@@ -1,60 +1,60 @@
# Manage file modes. This state should support different formats
# for specification (e.g., u+rwx, or -0011), but for now only supports
# specifying the full mode.
module Puppet
Puppet::Type.type(:file).newproperty(:mode) do
desc "Mode the file should be. Currently relatively limited:
you must specify the exact mode the file should be.
Note that when you set the mode of a directory, Puppet always
sets the search/traverse (1) bit anywhere the read (4) bit is set.
This is almost always what you want: read allows you to list the
entries in a directory, and search/traverse allows you to access
(read/write/execute) those entries.) Because of this feature, you
can recursively make a directory and all of the files in it
world-readable by setting e.g.:
file { '/some/dir':
- mode => 644,
+ mode => 644,
recurse => true,
}
In this case all of the files underneath `/some/dir` will have
mode 644, and all of the directories will have mode 755."
validate do |value|
if value.is_a?(String) and value !~ /^[0-7]+$/
raise Puppet::Error, "File modes can only be octal numbers, not #{should.inspect}"
end
end
munge do |should|
dirmask(should)
end
# If we're a directory, we need to be executable for all cases
# that are readable. This should probably be selectable, but eh.
def dirmask(value)
value = value.to_i(8) unless value.is_a? Integer
if FileTest.directory?(resource[:path])
value |= 0100 if value & 0400 != 0
value |= 010 if value & 040 != 0
value |= 01 if value & 04 != 0
end
value.to_s(8)
end
# If we're not following links and we're a link, then we just turn
# off mode management entirely.
def insync?(currentvalue)
if stat = @resource.stat and stat.ftype == "link" and @resource[:links] != :follow
self.debug "Not managing symlink mode"
return true
else
return super(currentvalue)
end
end
end
end
diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb
index 2080b9ee1..9375550a9 100755
--- a/lib/puppet/type/file/source.rb
+++ b/lib/puppet/type/file/source.rb
@@ -1,203 +1,204 @@
require 'puppet/file_serving/content'
require 'puppet/file_serving/metadata'
module Puppet
# Copy files from a local or remote source. This state *only* does any work
# when the remote file is an actual file; in that case, this state copies
# the file down. If the remote file is a dir or a link or whatever, then
# this state, during retrieval, modifies the appropriate other states
# so that things get taken care of appropriately.
Puppet::Type.type(:file).newparam(:source) do
include Puppet::Util::Diff
attr_accessor :source, :local
- desc "Copy a file over the current file. Uses `checksum` to
+ desc <<-EOT
+ Copy a file over the current file. Uses `checksum` to
determine when a file should be copied. Valid values are either
fully qualified paths to files, or URIs. Currently supported URI
types are *puppet* and *file*.
This is one of the primary mechanisms for getting content into
applications that Puppet does not directly support and is very
useful for those configuration files that don't change much across
sytems. For instance:
class sendmail {
- file { \"/etc/mail/sendmail.cf\":
- source => \"puppet://server/modules/module_name/sendmail.cf\"
+ file { "/etc/mail/sendmail.cf":
+ source => "puppet://server/modules/module_name/sendmail.cf"
}
}
You can also leave out the server name, in which case `puppet agent`
will fill in the name of its configuration server and `puppet apply`
will use the local filesystem. This makes it easy to use the same
configuration in both local and centralized forms.
Currently, only the `puppet` scheme is supported for source
URL's. Puppet will connect to the file server running on
`server` to retrieve the contents of the file. If the
`server` part is empty, the behavior of the command-line
interpreter (`puppet apply`) and the client demon (`puppet agent`) differs
slightly: `apply` will look such a file up on the module path
on the local host, whereas `agent` will connect to the
puppet server that it received the manifest from.
- See the [fileserver configuration documentation](http://docs.puppetlabs.com/guides/file_serving.html) for information on how to configure
- and use file services within Puppet.
+ See the [fileserver configuration documentation](http://docs.puppetlabs.com/guides/file_serving.html)
+ for information on how to configure and use file services within Puppet.
If you specify multiple file sources for a file, then the first
source that exists will be used. This allows you to specify
what amount to search paths for files:
- file { \"/path/to/my/file\":
+ file { "/path/to/my/file":
source => [
- \"/modules/nfs/files/file.$host\",
- \"/modules/nfs/files/file.$operatingsystem\",
- \"/modules/nfs/files/file\"
+ "/modules/nfs/files/file.$host",
+ "/modules/nfs/files/file.$operatingsystem",
+ "/modules/nfs/files/file"
]
}
This will use the first found file as the source.
You cannot currently copy links using this mechanism; set `links`
to `follow` if any remote sources are links.
- "
+ EOT
validate do |sources|
sources = [sources] unless sources.is_a?(Array)
sources.each do |source|
next if Puppet::Util.absolute_path?(source)
begin
uri = URI.parse(URI.escape(source))
rescue => detail
self.fail "Could not understand source #{source}: #{detail}"
end
self.fail "Cannot use relative URLs '#{source}'" unless uri.absolute?
self.fail "Cannot use opaque URLs '#{source}'" unless uri.hierarchical?
self.fail "Cannot use URLs of type '#{uri.scheme}' as source for fileserving" unless %w{file puppet}.include?(uri.scheme)
end
end
SEPARATOR_REGEX = [Regexp.escape(File::SEPARATOR.to_s), Regexp.escape(File::ALT_SEPARATOR.to_s)].join
munge do |sources|
sources = [sources] unless sources.is_a?(Array)
sources.map do |source|
source = source.sub(/[#{SEPARATOR_REGEX}]+$/, '')
if Puppet::Util.absolute_path?(source)
URI.unescape(Puppet::Util.path_to_uri(source).to_s)
else
source
end
end
end
def change_to_s(currentvalue, newvalue)
# newvalue = "{md5}#{@metadata.checksum}"
if @resource.property(:ensure).retrieve == :absent
return "creating from source #{metadata.source} with contents #{metadata.checksum}"
else
return "replacing from source #{metadata.source} with contents #{metadata.checksum}"
end
end
def checksum
metadata && metadata.checksum
end
# Look up (if necessary) and return remote content.
def content
return @content if @content
raise Puppet::DevError, "No source for content was stored with the metadata" unless metadata.source
unless tmp = Puppet::FileServing::Content.indirection.find(metadata.source)
fail "Could not find any content at %s" % metadata.source
end
@content = tmp.content
end
# Copy the values from the source to the resource. Yay.
def copy_source_values
devfail "Somehow got asked to copy source values without any metadata" unless metadata
# Take each of the stats and set them as states on the local file
# if a value has not already been provided.
[:owner, :mode, :group, :checksum].each do |metadata_method|
param_name = (metadata_method == :checksum) ? :content : metadata_method
next if metadata_method == :owner and !Puppet.features.root?
next if metadata_method == :checksum and metadata.ftype == "directory"
next if metadata_method == :checksum and metadata.ftype == "link" and metadata.links == :manage
if resource[param_name].nil? or resource[param_name] == :absent
resource[param_name] = metadata.send(metadata_method)
end
end
if resource[:ensure] == :absent
# We know all we need to
elsif metadata.ftype != "link"
resource[:ensure] = metadata.ftype
elsif @resource[:links] == :follow
resource[:ensure] = :present
else
resource[:ensure] = "link"
resource[:target] = metadata.destination
end
end
def found?
! (metadata.nil? or metadata.ftype.nil?)
end
attr_writer :metadata
# Provide, and retrieve if necessary, the metadata for this file. Fail
# if we can't find data about this host, and fail if there are any
# problems in our query.
def metadata
return @metadata if @metadata
return nil unless value
value.each do |source|
begin
if data = Puppet::FileServing::Metadata.indirection.find(source)
@metadata = data
@metadata.source = source
break
end
rescue => detail
fail detail, "Could not retrieve file metadata for #{source}: #{detail}"
end
end
fail "Could not retrieve information from environment #{Puppet[:environment]} source(s) #{value.join(", ")}" unless @metadata
@metadata
end
def local?
found? and scheme == "file"
end
def full_path
Puppet::Util.uri_to_path(uri) if found?
end
def server
(uri and uri.host) or Puppet.settings[:server]
end
def port
(uri and uri.port) or Puppet.settings[:masterport]
end
private
def scheme
(uri and uri.scheme)
end
def uri
@uri ||= URI.parse(URI.escape(metadata.source))
end
end
end
diff --git a/lib/puppet/type/file/target.rb b/lib/puppet/type/file/target.rb
index 7d391e672..017b4f4e9 100644
--- a/lib/puppet/type/file/target.rb
+++ b/lib/puppet/type/file/target.rb
@@ -1,87 +1,87 @@
module Puppet
Puppet::Type.type(:file).newproperty(:target) do
desc "The target for creating a link. Currently, symlinks are the
only type supported.
-
+
You can make relative links:
# (Useful on Solaris)
file { \"/etc/inetd.conf\":
ensure => link,
target => \"inet/inetd.conf\",
}
-
+
You can also make recursive symlinks, which will create a
directory structure that maps to the target directory,
with directories corresponding to each directory
and links corresponding to each file."
newvalue(:notlink) do
# We do nothing if the value is absent
return :nochange
end
# Anything else, basically
newvalue(/./) do
@resource[:ensure] = :link if ! @resource.should(:ensure)
# Only call mklink if ensure didn't call us in the first place.
currentensure = @resource.property(:ensure).retrieve
mklink if @resource.property(:ensure).safe_insync?(currentensure)
end
# Create our link.
def mklink
raise Puppet::Error, "Cannot symlink on Microsoft Windows" if Puppet.features.microsoft_windows?
target = self.should
# Clean up any existing objects. The argument is just for logging,
# it doesn't determine what's removed.
@resource.remove_existing(target)
raise Puppet::Error, "Could not remove existing file" if FileTest.exists?(@resource[:path])
Dir.chdir(File.dirname(@resource[:path])) do
Puppet::Util::SUIDManager.asuser(@resource.asuser) do
mode = @resource.should(:mode)
if mode
Puppet::Util.withumask(000) do
File.symlink(target, @resource[:path])
end
else
File.symlink(target, @resource[:path])
end
end
@resource.send(:property_fix)
:link_created
end
end
def insync?(currentvalue)
if [:nochange, :notlink].include?(self.should) or @resource.recurse?
return true
elsif ! @resource.replace? and File.exists?(@resource[:path])
return true
else
return super(currentvalue)
end
end
def retrieve
if stat = @resource.stat
if stat.ftype == "link"
return File.readlink(@resource[:path])
else
return :notlink
end
else
return :absent
end
end
end
end
diff --git a/lib/puppet/type/filebucket.rb b/lib/puppet/type/filebucket.rb
index 59174161b..6fe15ca7e 100755
--- a/lib/puppet/type/filebucket.rb
+++ b/lib/puppet/type/filebucket.rb
@@ -1,102 +1,102 @@
module Puppet
require 'puppet/file_bucket/dipper'
newtype(:filebucket) do
@doc = "A repository for backing up files. If no filebucket is
defined, then files will be backed up in their current directory,
but the filebucket can be either a host- or site-global repository
for backing up. It stores files and returns the MD5 sum, which
can later be used to retrieve the file if restoration becomes
necessary. A filebucket does not do any work itself; instead,
it can be specified as the value of *backup* in a **file** object.
Currently, filebuckets are only useful for manual retrieval of
accidentally removed files (e.g., you look in the log for the md5 sum
and retrieve the file with that sum from the filebucket), but when
transactions are fully supported filebuckets will be used to undo
transactions.
You will normally want to define a single filebucket for your
whole network and then use that as the default backup location:
# Define the bucket
filebucket { 'main':
server => puppet,
path => false,
# Due to a known issue, path must be set to false for remote filebuckets.
}
# Specify it as the default target
File { backup => main }
Puppetmaster servers create a filebucket by default, so this will
work in a default configuration."
newparam(:name) do
desc "The name of the filebucket."
isnamevar
end
newparam(:server) do
desc "The server providing the remote filebucket. If this is not
specified then *path* is checked. If it is set, then the
bucket is local. Otherwise the puppetmaster server specified
in the config or at the commandline is used.
-
+
Due to a known issue, you currently must set the `path` attribute to
false if you wish to specify a `server` attribute."
defaultto { Puppet[:server] }
end
newparam(:port) do
desc "The port on which the remote server is listening.
Defaults to the normal Puppet port, %s." % Puppet[:masterport]
defaultto { Puppet[:masterport] }
end
newparam(:path) do
desc "The path to the local filebucket. If this is
unset, then the bucket is remote. The parameter *server* must
can be specified to set the remote server."
defaultto { Puppet[:clientbucketdir] }
end
# Create a default filebucket.
def self.mkdefaultbucket
new(:name => "puppet", :path => Puppet[:clientbucketdir])
end
def bucket
mkbucket unless defined?(@bucket)
@bucket
end
private
def mkbucket
# Default is a local filebucket, if no server is given.
# If the default path has been removed, too, then
# the puppetmaster is used as default server
type = "local"
args = {}
if self[:path]
args[:Path] = self[:path]
else
args[:Server] = self[:server]
args[:Port] = self[:port]
end
begin
@bucket = Puppet::FileBucket::Dipper.new(args)
rescue => detail
puts detail.backtrace if Puppet[:trace]
self.fail("Could not create #{type} filebucket: #{detail}")
end
@bucket.name = self.name
end
end
end
diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb
index 9ad420b19..8fd5761aa 100755
--- a/lib/puppet/type/group.rb
+++ b/lib/puppet/type/group.rb
@@ -1,146 +1,145 @@
require 'etc'
require 'facter'
require 'puppet/property/keyvalue'
module Puppet
newtype(:group) do
@doc = "Manage groups. On most platforms this can only create groups.
Group membership must be managed on individual users.
On some platforms such as OS X, group membership is managed as an
attribute of the group, not the user record. Providers must have
the feature 'manages_members' to manage the 'members' property of
a group record."
feature :manages_members,
"For directories where membership is an attribute of groups not users."
feature :manages_aix_lam,
"The provider can manage AIX Loadable Authentication Module (LAM) system."
feature :system_groups,
"The provider allows you to create system groups with lower GIDs."
ensurable do
desc "Create or remove the group."
newvalue(:present) do
provider.create
end
newvalue(:absent) do
provider.delete
end
end
newproperty(:gid) do
desc "The group ID. Must be specified numerically. If not
specified, a number will be picked, which can result in ID
differences across systems and thus is not recommended. The
GID is picked according to local system standards.
On Windows, the property will return the group's security
identifier (SID)."
def retrieve
provider.gid
end
def sync
if self.should == :absent
raise Puppet::DevError, "GID cannot be deleted"
else
provider.gid = self.should
end
end
munge do |gid|
case gid
when String
if gid =~ /^[-0-9]+$/
gid = Integer(gid)
else
self.fail "Invalid GID #{gid}"
end
when Symbol
unless gid == :absent
self.devfail "Invalid GID #{gid}"
end
end
return gid
end
end
newproperty(:members, :array_matching => :all, :required_features => :manages_members) do
desc "The members of the group. For directory services where group
membership is stored in the group objects, not the users."
def change_to_s(currentvalue, newvalue)
currentvalue = currentvalue.join(",") if currentvalue != :absent
newvalue = newvalue.join(",")
super(currentvalue, newvalue)
end
end
newparam(:auth_membership) do
desc "whether the provider is authoritative for group membership."
defaultto true
end
newparam(:name) do
- desc "The group name. While naming limitations vary by
- system, it is advisable to keep the name to the degenerate
- limitations, which is a maximum of 8 characters beginning with
- a letter."
+ desc "The group name. While naming limitations vary by operating system,
+ it is advisable to restrict names to the lowest common denominator,
+ which is a maximum of 8 characters beginning with a letter."
isnamevar
end
newparam(:allowdupe, :boolean => true) do
desc "Whether to allow duplicate GIDs. This option does not work on
FreeBSD (contract to the `pw` man page)."
newvalues(:true, :false)
defaultto false
end
newparam(:ia_load_module, :required_features => :manages_aix_lam) do
desc "The name of the I&A module to use to manage this user"
end
newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
- desc "Specify group AIX attributes in an array of keyvalue pairs"
+ desc "Specify group AIX attributes in an array of `key=value` pairs."
def membership
:attribute_membership
end
def delimiter
" "
end
validate do |value|
raise ArgumentError, "Attributes value pairs must be seperated by an =" unless value.include?("=")
end
end
newparam(:attribute_membership) do
desc "Whether specified attribute value pairs should be treated as the only attributes
of the user or whether they should merely
be treated as the minimum list."
newvalues(:inclusive, :minimum)
defaultto :minimum
end
newparam(:system, :boolean => true) do
desc "Whether the group is a system group with lower GID."
newvalues(:true, :false)
defaultto false
end
end
end
diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb
index a770edab9..8f6aa9ad3 100755
--- a/lib/puppet/type/host.rb
+++ b/lib/puppet/type/host.rb
@@ -1,73 +1,73 @@
require 'puppet/property/ordered_list'
module Puppet
newtype(:host) do
ensurable
newproperty(:ip) do
desc "The host's IP address, IPv4 or IPv6."
validate do |value|
unless value =~ /^((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})$/
raise Puppet::Error, "Invalid IP address"
end
end
end
# for now we use OrderedList to indicate that the order does matter.
newproperty(:host_aliases, :parent => Puppet::Property::OrderedList) do
desc "Any aliases the host might have. Multiple values must be
specified as an array."
def delimiter
" "
end
def inclusive?
true
end
validate do |value|
raise Puppet::Error, "Host aliases cannot include whitespace" if value =~ /\s/
raise Puppet::Error, "Host alias cannot be an empty string. Use an empty array to delete all host_aliases " if value =~ /^\s*$/
end
end
newproperty(:comment) do
- desc "A comment that will be attached to the line with a # character"
+ desc "A comment that will be attached to the line with a # character."
end
newproperty(:target) do
desc "The file in which to store service information. Only used by
those providers that write to disk. On most systems this defaults to `/etc/hosts`."
defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
@resource.class.defaultprovider.default_target
else
nil
end
}
end
newparam(:name) do
desc "The host name."
isnamevar
validate do |value|
# LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
x = value.split('.').each do |hostpart|
unless hostpart =~ /^([\d\w]+|[\d\w][\d\w\-]+[\d\w])$/
raise Puppet::Error, "Invalid host name"
end
end
end
end
@doc = "Installs and manages host entries. For most systems, these
entries will just be in `/etc/hosts`, but some systems (notably OS X)
will have different solutions."
end
end
diff --git a/lib/puppet/type/interface.rb b/lib/puppet/type/interface.rb
index d3b5cb06f..40fb8176b 100644
--- a/lib/puppet/type/interface.rb
+++ b/lib/puppet/type/interface.rb
@@ -1,109 +1,112 @@
#
# Manages an interface on a given router or switch
#
require 'puppet/util/network_device/ipcalc'
Puppet::Type.newtype(:interface) do
@doc = "This represents a router or switch interface. It is possible to manage
- interface mode (access or trunking, native vlan and encapsulation),
+ interface mode (access or trunking, native vlan and encapsulation) and
switchport characteristics (speed, duplex)."
apply_to_device
ensurable do
defaultvalues
aliasvalue :shutdown, :absent
aliasvalue :no_shutdown, :present
defaultto { :no_shutdown }
end
newparam(:name) do
- desc "Interface name"
+ desc "The interface's name."
end
newparam(:device_url) do
- desc "Url to connect to a router or switch."
+ desc "The URL at which the router or switch can be reached."
end
newproperty(:description) do
desc "Interface description."
defaultto { @resource[:name] }
end
newproperty(:speed) do
desc "Interface speed."
newvalues(:auto, /^\d+/)
end
newproperty(:duplex) do
desc "Interface duplex."
newvalues(:auto, :full, :half)
end
newproperty(:native_vlan) do
desc "Interface native vlan (for access mode only)."
newvalues(/^\d+/)
end
newproperty(:encapsulation) do
desc "Interface switchport encapsulation."
newvalues(:none, :dot1q, :isl )
end
newproperty(:mode) do
desc "Interface switchport mode."
newvalues(:access, :trunk)
end
newproperty(:allowed_trunk_vlans) do
desc "Allowed list of Vlans that this trunk can forward."
newvalues(:all, /./)
end
newproperty(:etherchannel) do
desc "Channel group this interface is part of."
newvalues(/^\d+/)
end
newproperty(:ipaddress, :array_matching => :all) do
include Puppet::Util::NetworkDevice::IPCalc
- desc "IP Address of this interface (it might not be possible to set an interface IP address
- it depends on the interface type and device type).
+ desc "IP Address of this interface. Note that it might not be possible to set
+ an interface IP address; it depends on the interface type and device type.
+
Valid format of ip addresses are:
- * IPV4, like 127.0.0.1
- * IPV4/prefixlength like 127.0.1.1/24
- * IPV6/prefixlength like FE80::21A:2FFF:FE30:ECF0/128
- * an optional suffix for IPV6 addresses from this list: eui-64, link-local
- It is also possible to use an array of values.
+
+ * IPV4, like 127.0.0.1
+ * IPV4/prefixlength like 127.0.1.1/24
+ * IPV6/prefixlength like FE80::21A:2FFF:FE30:ECF0/128
+ * an optional suffix for IPV6 addresses from this list: `eui-64`, `link-local`
+
+ It is also possible to supply an array of values.
"
validate do |values|
values = [values] unless values.is_a?(Array)
values.each do |value|
self.fail "Invalid interface ip address" unless parse(value.gsub(/\s*(eui-64|link-local)\s*$/,''))
end
end
munge do |value|
option = value =~ /eui-64|link-local/i ? value.gsub(/^.*?\s*(eui-64|link-local)\s*$/,'\1') : nil
[parse(value.gsub(/\s*(eui-64|link-local)\s*$/,'')), option].flatten
end
def value_to_s(value)
value = [value] unless value.is_a?(Array)
value.map{ |v| "#{v[1].to_s}/#{v[0]} #{v[2]}"}.join(",")
end
def change_to_s(currentvalue, newvalue)
currentvalue = value_to_s(currentvalue) if currentvalue != :absent
newvalue = value_to_s(newvalue)
super(currentvalue, newvalue)
end
end
end
diff --git a/lib/puppet/type/k5login.rb b/lib/puppet/type/k5login.rb
index 2e87ca907..09114e977 100644
--- a/lib/puppet/type/k5login.rb
+++ b/lib/puppet/type/k5login.rb
@@ -1,87 +1,87 @@
# Plug-in type for handling k5login files
Puppet::Type.newtype(:k5login) do
@doc = "Manage the `.k5login` file for a user. Specify the full path to
- the `.k5login` file as the name and an array of principals as the
- property principals."
+ the `.k5login` file as the name, and an array of principals as the
+ `principals` attribute."
ensurable
# Principals that should exist in the file
newproperty(:principals, :array_matching => :all) do
- desc "The principals present in the `.k5login` file."
+ desc "The principals present in the `.k5login` file. This should be specified as an array."
end
# The path/name of the k5login file
newparam(:path) do
isnamevar
- desc "The path to the file to manage. Must be fully qualified."
+ desc "The path to the `.k5login` file to manage. Must be fully qualified."
validate do |value|
unless value =~ /^#{File::SEPARATOR}/
- raise Puppet::Error, "File paths must be fully qualified"
+ raise Puppet::Error, "File paths must be fully qualified."
end
end
end
# To manage the mode of the file
newproperty(:mode) do
- desc "Manage the k5login file's mode"
+ desc "The desired permissions mode of the `.k5login` file. Defaults to `644`."
defaultto { "644" }
end
provide(:k5login) do
desc "The k5login provider is the only provider for the k5login
type."
# Does this file exist?
def exists?
File.exists?(@resource[:name])
end
# create the file
def create
write(@resource.should(:principals))
should_mode = @resource.should(:mode)
unless self.mode == should_mode
self.mode = should_mode
end
end
# remove the file
def destroy
File.unlink(@resource[:name])
end
# Return the principals
def principals(dummy_argument=:work_arround_for_ruby_GC_bug)
if File.exists?(@resource[:name])
File.readlines(@resource[:name]).collect { |line| line.chomp }
else
:absent
end
end
# Write the principals out to the k5login file
def principals=(value)
write(value)
end
# Return the mode as an octal string, not as an integer
def mode
"%o" % (File.stat(@resource[:name]).mode & 007777)
end
# Set the file mode, converting from a string to an integer.
def mode=(value)
File.chmod(Integer("0#{value}"), @resource[:name])
end
private
def write(value)
Puppet::Util.secure_open(@resource[:name], "w") do |f|
f.puts value.join("\n")
end
end
end
end
diff --git a/lib/puppet/type/macauthorization.rb b/lib/puppet/type/macauthorization.rb
index b16ab6dde..9504542d9 100644
--- a/lib/puppet/type/macauthorization.rb
+++ b/lib/puppet/type/macauthorization.rb
@@ -1,166 +1,167 @@
Puppet::Type.newtype(:macauthorization) do
- @doc = "Manage the Mac OS X authorization database.
- See the [Apple developer site](http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html) for more information.
+ @doc = "Manage the Mac OS X authorization database. See the
+ [Apple developer site](http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html)
+ for more information.
+
+ Note that authorization store directives with hyphens in their names have
+ been renamed to use underscores, as Puppet does not react well to hyphens
+ in identifiers.
**Autorequires:** If Puppet is managing the `/etc/authorization` file, each
macauthorization resource will autorequire it."
ensurable
autorequire(:file) do
["/etc/authorization"]
end
def munge_boolean(value)
case value
when true, "true", :true
:true
when false, "false", :false
:false
else
fail("munge_boolean only takes booleans")
end
end
def munge_integer(value)
Integer(value)
rescue ArgumentError
fail("munge_integer only takes integers")
end
newparam(:name) do
desc "The name of the right or rule to be managed.
- Corresponds to 'key' in Authorization Services. The key is the name
+ Corresponds to `key` in Authorization Services. The key is the name
of a rule. A key uses the same naming conventions as a right. The
Security Server uses a rule's key to match the rule with a right.
Wildcard keys end with a '.'. The generic rule has an empty key value.
Any rights that do not match a specific rule use the generic rule."
isnamevar
end
newproperty(:auth_type) do
- desc "type - can be a 'right' or a 'rule'. 'comment' has not yet been
- implemented."
+ desc "Type --- this can be a `right` or a `rule`. The `comment` type has
+ not yet been implemented."
newvalue(:right)
newvalue(:rule)
# newvalue(:comment) # not yet implemented.
end
newproperty(:allow_root, :boolean => true) do
- desc "Corresponds to 'allow-root' in the authorization store, renamed
- due to hyphens being problematic. Specifies whether a right should be
- allowed automatically if the requesting process is running with
- uid == 0. AuthorizationServices defaults this attribute to false if
- not specified"
+ desc "Corresponds to `allow-root` in the authorization store. Specifies
+ whether a right should be allowed automatically if the requesting process
+ is running with `uid == 0`. AuthorizationServices defaults this attribute
+ to false if not specified."
newvalue(:true)
newvalue(:false)
munge do |value|
@resource.munge_boolean(value)
end
end
newproperty(:authenticate_user, :boolean => true) do
- desc "Corresponds to 'authenticate-user' in the authorization store,
- renamed due to hyphens being problematic."
+ desc "Corresponds to `authenticate-user` in the authorization store."
newvalue(:true)
newvalue(:false)
munge do |value|
@resource.munge_boolean(value)
end
end
newproperty(:auth_class) do
- desc "Corresponds to 'class' in the authorization store, renamed due
- to 'class' being a reserved word."
+ desc "Corresponds to `class` in the authorization store; renamed due
+ to 'class' being a reserved word in Puppet."
newvalue(:user)
newvalue(:'evaluate-mechanisms')
newvalue(:allow)
newvalue(:deny)
newvalue(:rule)
end
newproperty(:comment) do
- desc "The 'comment' attribute for authorization resources."
+ desc "The `comment` attribute for authorization resources."
end
newproperty(:group) do
- desc "The user must authenticate as a member of this group. This
- attribute can be set to any one group."
+ desc "A group which the user must authenticate as a member of. This
+ must be a single group."
end
newproperty(:k_of_n) do
- desc "k-of-n describes how large a subset of rule mechanisms must
- succeed for successful authentication. If there are 'n' mechanisms,
- then 'k' (the integer value of this parameter) mechanisms must succeed.
- The most common setting for this parameter is '1'. If k-of-n is not
- set, then 'n-of-n' mechanisms must succeed."
+ desc "How large a subset of rule mechanisms must succeed for successful
+ authentication. If there are 'n' mechanisms, then 'k' (the integer value
+ of this parameter) mechanisms must succeed. The most common setting for
+ this parameter is `1`. If `k-of-n` is not set, then every mechanism ---
+ that is, 'n-of-n' --- must succeed."
munge do |value|
@resource.munge_integer(value)
end
end
newproperty(:mechanisms, :array_matching => :all) do
- desc "an array of suitable mechanisms."
+ desc "An array of suitable mechanisms."
end
newproperty(:rule, :array_matching => :all) do
desc "The rule(s) that this right refers to."
end
newproperty(:session_owner, :boolean => true) do
- desc "Corresponds to 'session-owner' in the authorization store,
- renamed due to hyphens being problematic. Whether the session owner
- automatically matches this rule or right."
+ desc "Whether the session owner automatically matches this rule or right.
+ Corresponds to `session-owner` in the authorization store."
newvalue(:true)
newvalue(:false)
munge do |value|
@resource.munge_boolean(value)
end
end
newproperty(:shared, :boolean => true) do
- desc "If this is set to true, then the Security Server marks the
- credentials used to gain this right as shared. The Security Server
- may use any shared credentials to authorize this right. For maximum
- security, set sharing to false so credentials stored by the Security
- Server for one application may not be used by another application."
+ desc "Whether the Security Server should mark the credentials used to gain
+ this right as shared. The Security Server may use any shared credentials
+ to authorize this right. For maximum security, set sharing to false so
+ credentials stored by the Security Server for one application may not be
+ used by another application."
newvalue(:true)
newvalue(:false)
munge do |value|
@resource.munge_boolean(value)
end
end
newproperty(:timeout) do
- desc "The credential used by this rule expires in the specified
- number of seconds. For maximum security where the user must
- authenticate every time, set the timeout to 0. For minimum security,
- remove the timeout attribute so the user authenticates only once per
- session."
+ desc "The number of seconds in which the credential used by this rule will
+ expire. For maximum security where the user must authenticate every time,
+ set the timeout to 0. For minimum security, remove the timeout attribute
+ so the user authenticates only once per session."
munge do |value|
@resource.munge_integer(value)
end
end
newproperty(:tries) do
desc "The number of tries allowed."
munge do |value|
@resource.munge_integer(value)
end
end
end
diff --git a/lib/puppet/type/maillist.rb b/lib/puppet/type/maillist.rb
index 732fbf09f..4e0542c83 100755
--- a/lib/puppet/type/maillist.rb
+++ b/lib/puppet/type/maillist.rb
@@ -1,62 +1,62 @@
module Puppet
newtype(:maillist) do
- @doc = "Manage email lists. This resource type currently can only create
- and remove lists, it cannot reconfigure them."
+ @doc = "Manage email lists. This resource type can only create
+ and remove lists; it cannot currently reconfigure them."
ensurable do
defaultvalues
newvalue(:purged) do
provider.purge
end
def change_to_s(current_value, newvalue)
return "Purged #{resource}" if newvalue == :purged
super
end
def insync?(is)
return true if is == :absent && should == :purged
super
end
end
newparam(:name, :namevar => true) do
desc "The name of the email list."
end
newparam(:description) do
desc "The description of the mailing list."
end
newparam(:password) do
desc "The admin password."
end
newparam(:webserver) do
desc "The name of the host providing web archives and the administrative interface."
end
newparam(:mailserver) do
desc "The name of the host handling email for the list."
end
newparam(:admin) do
desc "The email address of the administrator."
end
def generate
if provider.respond_to?(:aliases)
should = self.should(:ensure) || :present
if should == :purged
should = :absent
end
atype = Puppet::Type.type(:mailalias)
provider.aliases.
reject { |name,recipient| catalog.resource(:mailalias, name) }.
collect { |name,recipient| atype.new(:name => name, :recipient => recipient, :ensure => should) }
end
end
end
end
diff --git a/lib/puppet/type/mcx.rb b/lib/puppet/type/mcx.rb
index d0306ca46..f9213c115 100644
--- a/lib/puppet/type/mcx.rb
+++ b/lib/puppet/type/mcx.rb
@@ -1,99 +1,99 @@
Puppet::Type.newtype(:mcx) do
@doc = "MCX object management using DirectoryService on OS X.
The default provider of this type merely manages the XML plist as
-reported by the dscl -mcxexport command. This is similar to the
+reported by the `dscl -mcxexport` command. This is similar to the
content property of the file type in Puppet.
The recommended method of using this type is to use Work Group Manager
to manage users and groups on the local computer, record the resulting
puppet manifest using the command `puppet resource mcx`, then deploy it
to other machines.
**Autorequires:** If Puppet is managing the user, group, or computer that these
MCX settings refer to, the MCX resource will autorequire that user, group, or computer.
"
feature :manages_content, \
"The provider can manage MCXSettings as a string.",
:methods => [:content, :content=]
ensurable do
desc "Create or remove the MCX setting."
newvalue(:present) do
provider.create
end
newvalue(:absent) do
provider.destroy
end
end
newparam(:name) do
desc "The name of the resource being managed.
The default naming convention follows Directory Service paths:
/Computers/localhost
/Groups/admin
/Users/localadmin
The `ds_type` and `ds_name` type parameters are not necessary if the
default naming convention is followed."
isnamevar
end
newparam(:ds_type) do
desc "The DirectoryService type this MCX setting attaches to."
newvalues(:user, :group, :computer, :computerlist)
end
newparam(:ds_name) do
- desc "The name to attach the MCX Setting to.
- e.g. 'localhost' when ds_type => computer. This setting is not
- required, as it may be parsed so long as the resource name is
- parseable. e.g. /Groups/admin where 'group' is the dstype."
+ desc "The name to attach the MCX Setting to. (For example, `localhost`
+ when `ds_type => computer`.) This setting is not required, as it can be
+ automatically discovered when the resource name is parseable. (For
+ example, in `/Groups/admin`, `group` will be used as the dstype.)"
end
newproperty(:content, :required_features => :manages_content) do
- desc "The XML Plist. The value of MCXSettings in DirectoryService.
+ desc "The XML Plist used as the value of MCXSettings in DirectoryService.
This is the standard output from the system command:
dscl localhost -mcxexport /Local/Default/<ds_type>/ds_name
Note that `ds_type` is capitalized and plural in the dscl command."
end
# JJM Yes, this is not DRY at all. Because of the code blocks
# autorequire must be done this way. I think.
def setup_autorequire(type)
# value returns a Symbol
name = value(:name)
ds_type = value(:ds_type)
ds_name = value(:ds_name)
if ds_type == type
rval = [ ds_name.to_s ]
else
rval = [ ]
end
rval
end
autorequire(:user) do
setup_autorequire(:user)
end
autorequire(:group) do
setup_autorequire(:group)
end
autorequire(:computer) do
setup_autorequire(:computer)
end
end
diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb
index 5b8c5ca58..58c320806 100755
--- a/lib/puppet/type/mount.rb
+++ b/lib/puppet/type/mount.rb
@@ -1,240 +1,241 @@
module Puppet
# We want the mount to refresh when it changes.
newtype(:mount, :self_refresh => true) do
@doc = "Manages mounted filesystems, including putting mount
information into the mount table. The actual behavior depends
on the value of the 'ensure' parameter.
Note that if a `mount` receives an event from another resource,
it will try to remount the filesystems if `ensure` is set to `mounted`."
feature :refreshable, "The provider can remount the filesystem.",
:methods => [:remount]
# Use the normal parent class, because we actually want to
# call code when sync is called.
newproperty(:ensure) do
desc "Control what to do with this mount. Set this attribute to
`umounted` to make sure the filesystem is in the filesystem table
- but not mounted (if the filesystem is currently mounted, it will be unmounted). Set it to `absent` to unmount (if necessary) and remove
+ but not mounted (if the filesystem is currently mounted, it will be
+ unmounted). Set it to `absent` to unmount (if necessary) and remove
the filesystem from the fstab. Set to `mounted` to add it to the
fstab and mount it. Set to `present` to add to fstab but not change
- mount/unmount status"
+ mount/unmount status."
# IS -> SHOULD In Sync Action
# ghost -> present NO create
# absent -> present NO create
# (mounted -> present YES)
# (unmounted -> present YES)
newvalue(:defined) do
provider.create
return :mount_created
end
aliasvalue :present, :defined
# IS -> SHOULD In Sync Action
# ghost -> unmounted NO create, unmount
# absent -> unmounted NO create
# mounted -> unmounted NO unmount
newvalue(:unmounted) do
case self.retrieve
when :ghost # (not in fstab but mounted)
provider.create
@resource.flush
provider.unmount
return :mount_unmounted
when nil, :absent # (not in fstab and not mounted)
provider.create
return :mount_created
when :mounted # (in fstab and mounted)
provider.unmount
syncothers # I guess it's more likely that the mount was originally mounted with
# the wrong attributes so I sync AFTER the umount
return :mount_unmounted
else
raise Puppet::Error, "Unexpected change from #{current_value} to unmounted}"
end
end
# IS -> SHOULD In Sync Action
# ghost -> absent NO unmount
# mounted -> absent NO provider.destroy AND unmount
# unmounted -> absent NO provider.destroy
newvalue(:absent, :event => :mount_deleted) do
current_value = self.retrieve
provider.unmount if provider.mounted?
provider.destroy unless current_value == :ghost
end
# IS -> SHOULD In Sync Action
# ghost -> mounted NO provider.create
# absent -> mounted NO provider.create AND mount
# unmounted -> mounted NO mount
newvalue(:mounted, :event => :mount_mounted) do
# Create the mount point if it does not already exist.
current_value = self.retrieve
currently_mounted = provider.mounted?
provider.create if [nil, :absent, :ghost].include?(current_value)
syncothers
# The fs can be already mounted if it was absent but mounted
provider.property_hash[:needs_mount] = true unless currently_mounted
end
# insync: mounted -> present
# unmounted -> present
def insync?(is)
if should == :defined and [:mounted,:unmounted].include?(is)
true
else
super
end
end
def syncothers
# We have to flush any changes to disk.
currentvalues = @resource.retrieve_resource
# Determine if there are any out-of-sync properties.
oos = @resource.send(:properties).find_all do |prop|
unless currentvalues.include?(prop)
raise Puppet::DevError, "Parent has property %s but it doesn't appear in the current values", [prop.name]
end
if prop.name == :ensure
false
else
! prop.safe_insync?(currentvalues[prop])
end
end.each { |prop| prop.sync }.length
@resource.flush if oos > 0
end
end
newproperty(:device) do
desc "The device providing the mount. This can be whatever
device is supporting by the mount, including network
devices or devices specified by UUID rather than device
path, depending on the operating system."
end
# Solaris specifies two devices, not just one.
newproperty(:blockdevice) do
desc "The device to fsck. This is property is only valid
on Solaris, and in most cases will default to the correct
value."
# Default to the device but with "dsk" replaced with "rdsk".
defaultto do
if Facter["operatingsystem"].value == "Solaris"
device = @resource.value(:device)
if device =~ %r{/dsk/}
device.sub(%r{/dsk/}, "/rdsk/")
else
nil
end
else
nil
end
end
end
newproperty(:fstype) do
desc "The mount type. Valid values depend on the
operating system. This is a required option."
end
newproperty(:options) do
desc "Mount options for the mounts, as they would
appear in the fstab."
end
newproperty(:pass) do
desc "The pass in which the mount is checked."
defaultto {
0 if @resource.managed?
}
end
newproperty(:atboot) do
desc "Whether to mount the mount at boot. Not all platforms
support this."
end
newproperty(:dump) do
desc "Whether to dump the mount. Not all platform support this.
Valid values are `1` or `0`. or `2` on FreeBSD, Default is `0`."
if Facter["operatingsystem"].value == "FreeBSD"
newvalue(%r{(0|1|2)})
else
newvalue(%r{(0|1)})
end
newvalue(%r{(0|1)})
defaultto {
0 if @resource.managed?
}
end
newproperty(:target) do
desc "The file in which to store the mount table. Only used by
those providers that write to disk."
defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
@resource.class.defaultprovider.default_target
else
nil
end
}
end
newparam(:name) do
desc "The mount path for the mount."
isnamevar
end
newparam(:path) do
desc "The deprecated name for the mount point. Please use `name` now."
def value=(value)
warning "'path' is deprecated for mounts. Please use 'name'."
@resource[:name] = value
super
end
end
newparam(:remounts) do
desc "Whether the mount can be remounted `mount -o remount`. If
this is false, then the filesystem will be unmounted and remounted
manually, which is prone to failure."
newvalues(:true, :false)
defaultto do
case Facter.value(:operatingsystem)
when "FreeBSD", "Darwin", "AIX"
false
else
true
end
end
end
def refresh
# Only remount if we're supposed to be mounted.
provider.remount if self.should(:fstype) != "swap" and provider.mounted?
end
def value(name)
name = symbolize(name)
ret = nil
if property = @parameters[name]
return property.value
end
end
end
end
diff --git a/lib/puppet/type/notify.rb b/lib/puppet/type/notify.rb
index a6ec1dc8b..98da694d7 100644
--- a/lib/puppet/type/notify.rb
+++ b/lib/puppet/type/notify.rb
@@ -1,44 +1,44 @@
#
# Simple module for logging messages on the client-side
#
module Puppet
newtype(:notify) do
@doc = "Sends an arbitrary message to the agent run-time log."
newproperty(:message) do
desc "The message to be sent to the log."
def sync
case @resource["withpath"]
when :true
send(@resource[:loglevel], self.should)
else
Puppet.send(@resource[:loglevel], self.should)
end
return
end
def retrieve
:absent
end
def insync?(is)
false
end
defaultto { @resource[:name] }
end
newparam(:withpath) do
- desc "Whether to not to show the full object path."
+ desc "Whether to show the full object path. Defaults to false."
defaultto :false
newvalues(:true, :false)
end
newparam(:name) do
desc "An arbitrary tag for your own reference; the name of the message."
isnamevar
end
end
end
diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb
index a39aa696f..d0bdfdba1 100644
--- a/lib/puppet/type/package.rb
+++ b/lib/puppet/type/package.rb
@@ -1,337 +1,337 @@
# Define the different packaging systems. Each package system is implemented
# in a module, which then gets used to individually extend each package object.
# This allows packages to exist on the same machine using different packaging
# systems.
module Puppet
newtype(:package) do
@doc = "Manage packages. There is a basic dichotomy in package
- support right now: Some package types (e.g., yum and apt) can
- retrieve their own package files, while others (e.g., rpm and
- sun) cannot. For those package formats that cannot retrieve
- their own files, you can use the `source` parameter to point to
- the correct file.
+ support right now: Some package types (e.g., yum and apt) can
+ retrieve their own package files, while others (e.g., rpm and sun)
+ cannot. For those package formats that cannot retrieve their own files,
+ you can use the `source` parameter to point to the correct file.
Puppet will automatically guess the packaging format that you are
using based on the platform you are on, but you can override it
using the `provider` parameter; each provider defines what it
requires in order to function, and you must meet those requirements
to use a given provider.
**Autorequires:** If Puppet is managing the files specified as a
package's `adminfile`, `responsefile`, or `source`, the package
resource will autorequire those files."
feature :installable, "The provider can install packages.",
:methods => [:install]
feature :uninstallable, "The provider can uninstall packages.",
:methods => [:uninstall]
feature :upgradeable, "The provider can upgrade to the latest version of a
package. This feature is used by specifying `latest` as the
desired value for the package.",
:methods => [:update, :latest]
feature :purgeable, "The provider can purge packages. This generally means
that all traces of the package are removed, including
existing configuration files. This feature is thus destructive
and should be used with the utmost care.",
:methods => [:purge]
feature :versionable, "The provider is capable of interrogating the
package database for installed version(s), and can select
which out of a set of available versions of a package to
install if asked."
feature :holdable, "The provider is capable of placing packages on hold
such that they are not automatically upgraded as a result of
other package dependencies unless explicit action is taken by
a user or another package. Held is considered a superset of
installed.",
:methods => [:hold]
feature :install_options, "The provider accepts options to be
passed to the installer command."
ensurable do
- desc "What state the package should be in.
- *latest* only makes sense for those packaging formats that can
- retrieve new packages on their own and will throw an error on
- those that cannot. For those packaging systems that allow you
- to specify package versions, specify them here. Similarly,
- *purged* is only useful for packaging systems that support
- the notion of managing configuration files separately from
- 'normal' system files."
+ desc <<-EOT
+ What state the package should be in. On packaging systems that can
+ retrieve new packages on their own, you can choose which package to
+ retrieve by specifying a version number or `latest` as the ensure
+ value. On packaging systems that manage configuration files separately
+ from "normal" system files, you can uninstall config files by
+ specifying `purged` as the ensure value.
+ EOT
attr_accessor :latest
newvalue(:present, :event => :package_installed) do
provider.install
end
newvalue(:absent, :event => :package_removed) do
provider.uninstall
end
newvalue(:purged, :event => :package_purged, :required_features => :purgeable) do
provider.purge
end
newvalue(:held, :event => :package_held, :required_features => :holdable) do
provider.hold
end
# Alias the 'present' value.
aliasvalue(:installed, :present)
newvalue(:latest, :required_features => :upgradeable) do
# Because yum always exits with a 0 exit code, there's a retrieve
# in the "install" method. So, check the current state now,
# to compare against later.
current = self.retrieve
begin
provider.update
rescue => detail
self.fail "Could not update: #{detail}"
end
if current == :absent
:package_installed
else
:package_changed
end
end
newvalue(/./, :required_features => :versionable) do
begin
provider.install
rescue => detail
self.fail "Could not update: #{detail}"
end
if self.retrieve == :absent
:package_installed
else
:package_changed
end
end
defaultto :installed
# Override the parent method, because we've got all kinds of
# funky definitions of 'in sync'.
def insync?(is)
@latest ||= nil
@lateststamp ||= (Time.now.to_i - 1000)
# Iterate across all of the should values, and see how they
# turn out.
@should.each { |should|
case should
when :present
return true unless [:absent, :purged, :held].include?(is)
when :latest
# Short-circuit packages that are not present
return false if is == :absent or is == :purged
# Don't run 'latest' more than about every 5 minutes
if @latest and ((Time.now.to_i - @lateststamp) / 60) < 5
#self.debug "Skipping latest check"
else
begin
@latest = provider.latest
@lateststamp = Time.now.to_i
rescue => detail
error = Puppet::Error.new("Could not get latest version: #{detail}")
error.set_backtrace(detail.backtrace)
raise error
end
end
case is
when @latest
return true
when :present
# This will only happen on retarded packaging systems
# that can't query versions.
return true
else
self.debug "#{@resource.name} #{is.inspect} is installed, latest is #{@latest.inspect}"
end
when :absent
return true if is == :absent or is == :purged
when :purged
return true if is == :purged
when is
return true
end
}
false
end
# This retrieves the current state. LAK: I think this method is unused.
def retrieve
provider.properties[:ensure]
end
# Provide a bit more information when logging upgrades.
def should_to_s(newvalue = @should)
if @latest
@latest.to_s
else
super(newvalue)
end
end
end
newparam(:name) do
desc "The package name. This is the name that the packaging
system uses internally, which is sometimes (especially on Solaris)
a name that is basically useless to humans. If you want to
abstract package installation, then you can use aliases to provide
a common name to packages:
# In the 'openssl' class
$ssl = $operatingsystem ? {
solaris => SMCossl,
default => openssl
}
# It is not an error to set an alias to the same value as the
# object name.
package { $ssl:
ensure => installed,
- alias => openssl
+ alias => openssl
}
. etc. .
$ssh = $operatingsystem ? {
solaris => SMCossh,
default => openssh
}
# Use the alias to specify a dependency, rather than
# having another selector to figure it out again.
package { $ssh:
- ensure => installed,
- alias => openssh,
+ ensure => installed,
+ alias => openssh,
require => Package[openssl]
}
"
isnamevar
end
newparam(:source) do
desc "Where to find the actual package. This must be a local file
(or on a network file system) or a URL that your specific
- packaging type understands; Puppet will not retrieve files for you."
+ packaging type understands; Puppet will not retrieve files for you,
+ although you can manage packages as `file` resources."
validate do |value|
provider.validate_source(value)
end
end
newparam(:instance) do
desc "A read-only parameter set by the package."
end
newparam(:status) do
desc "A read-only parameter set by the package."
end
newparam(:type) do
desc "Deprecated form of `provider`."
munge do |value|
warning "'type' is deprecated; use 'provider' instead"
@resource[:provider] = value
@resource[:provider]
end
end
newparam(:adminfile) do
desc "A file containing package defaults for installing packages.
This is currently only used on Solaris. The value will be
validated according to system rules, which in the case of
Solaris means that it should either be a fully qualified path
or it should be in `/var/sadm/install/admin`."
end
newparam(:responsefile) do
desc "A file containing any necessary answers to questions asked by
the package. This is currently used on Solaris and Debian. The
value will be validated according to system rules, but it should
generally be a fully qualified path."
end
newparam(:configfiles) do
desc "Whether configfiles should be kept or replaced. Most packages
- types do not support this parameter."
+ types do not support this parameter. Defaults to `keep`."
defaultto :keep
newvalues(:keep, :replace)
end
newparam(:category) do
desc "A read-only parameter set by the package."
end
newparam(:platform) do
desc "A read-only parameter set by the package."
end
newparam(:root) do
desc "A read-only parameter set by the package."
end
newparam(:vendor) do
desc "A read-only parameter set by the package."
end
newparam(:description) do
desc "A read-only parameter set by the package."
end
newparam(:allowcdrom) do
desc "Tells apt to allow cdrom sources in the sources.list file.
Normally apt will bail if you try this."
newvalues(:true, :false)
end
newparam(:flavor) do
desc "Newer versions of OpenBSD support 'flavors', which are
further specifications for which type of package you want."
end
newparam(:install_options, :required_features => :install_options) do
desc "A hash of options to be handled by the provider when
installing a package."
end
autorequire(:file) do
autos = []
[:responsefile, :adminfile].each { |param|
if val = self[param]
autos << val
end
}
if source = self[:source]
if source =~ /^#{File::SEPARATOR}/
autos << source
end
end
autos
end
# This only exists for testing.
def clear
if obj = @parameters[:ensure]
obj.latest = nil
end
end
# The 'query' method returns a hash of info if the package
# exists and returns nil if it does not.
def exists?
@provider.get(:ensure) != :absent
end
end
end
diff --git a/lib/puppet/type/router.rb b/lib/puppet/type/router.rb
index 648389d39..6cd267b2d 100644
--- a/lib/puppet/type/router.rb
+++ b/lib/puppet/type/router.rb
@@ -1,14 +1,17 @@
#
# Manage a router abstraction
#
module Puppet
newtype(:router) do
@doc = "Manages connected router."
newparam(:url) do
- desc "An URL to access the router of the form (ssh|telnet)://user:pass:enable@host/."
+ desc <<-EOT
+ An SSH or telnet URL at which to access the router, in the form
+ `ssh://user:pass:enable@host/` or `telnet://user:pass:enable@host/`.
+ EOT
isnamevar
end
end
end
diff --git a/lib/puppet/type/schedule.rb b/lib/puppet/type/schedule.rb
index f60f96fd2..2baf726c7 100755
--- a/lib/puppet/type/schedule.rb
+++ b/lib/puppet/type/schedule.rb
@@ -1,351 +1,359 @@
module Puppet
newtype(:schedule) do
- @doc = "Defined schedules for Puppet. The important thing to understand
- about how schedules are currently implemented in Puppet is that they
- can only be used to stop a resource from being applied, they never
- guarantee that it is applied.
-
- Every time Puppet applies its configuration, it will collect the
- list of resources whose schedule does not eliminate them from
+ @doc = <<-EOT
+ Define schedules for Puppet. Resources can be limited to a schedule by using the
+ [`schedule`](http://docs.puppetlabs.com/references/latest/metaparameter.html#schedule)
+ metaparameter.
+
+ Currently, **schedules can only be used to stop a resource from being
+ applied;** they cannot cause a resource to be applied when it otherwise
+ wouldn't be, and they cannot accurately specify a time when a resource
+ should run.
+
+ Every time Puppet applies its configuration, it will apply the
+ set of resources whose schedule does not eliminate them from
running right then, but there is currently no system in place to
guarantee that a given resource runs at a given time. If you
specify a very restrictive schedule and Puppet happens to run at a
time within that schedule, then the resources will get applied;
otherwise, that work may never get done.
- Thus, it behooves you to use wider scheduling (e.g., over a couple of
+ Thus, it is advisable to use wider scheduling (e.g., over a couple of
hours) combined with periods and repetitions. For instance, if you
wanted to restrict certain resources to only running once, between
the hours of two and 4 AM, then you would use this schedule:
- schedule { maint:
- range => \"2 - 4\",
+ schedule { 'maint':
+ range => "2 - 4",
period => daily,
- repeat => 1
+ repeat => 1,
}
With this schedule, the first time that Puppet runs between 2 and 4 AM,
all resources with this schedule will get applied, but they won't
get applied again between 2 and 4 because they will have already
run once that day, and they won't get applied outside that schedule
because they will be outside the scheduled range.
- Puppet automatically creates a schedule for each valid period with the
- same name as that period (e.g., hourly and daily). Additionally,
- a schedule named *puppet* is created and used as the default,
- with the following attributes:
+ Puppet automatically creates a schedule for each of the valid periods
+ with the same name as that period (e.g., hourly and daily).
+ Additionally, a schedule named `puppet` is created and used as the
+ default, with the following attributes:
- schedule { puppet:
+ schedule { 'puppet':
period => hourly,
- repeat => 2
+ repeat => 2,
}
This will cause resources to be applied every 30 minutes by default.
- "
+ EOT
apply_to_all
newparam(:name) do
- desc "The name of the schedule. This name is used to retrieve the
+ desc <<-EOT
+ The name of the schedule. This name is used to retrieve the
schedule when assigning it to an object:
- schedule { daily:
+ schedule { 'daily':
period => daily,
- range => \"2 - 4\",
+ range => "2 - 4",
}
-
- exec { \"/usr/bin/apt-get update\":
- schedule => daily
+
+ exec { "/usr/bin/apt-get update":
+ schedule => 'daily',
}
- "
+ EOT
isnamevar
end
newparam(:range) do
- desc "The earliest and latest that a resource can be applied. This
- is always a range within a 24 hour period, and hours must be
- specified in numbers between 0 and 23, inclusive. Minutes and
- seconds can be provided, using the normal colon as a separator.
- For instance:
-
- schedule { maintenance:
- range => \"1:30 - 4:30\"
+ desc <<-EOT
+ The earliest and latest that a resource can be applied. This is
+ always a hyphen-separated range within a 24 hour period, and hours
+ must be specified in numbers between 0 and 23, inclusive. Minutes and
+ seconds can optionally be provided, using the normal colon as a
+ separator. For instance:
+
+ schedule { 'maintenance':
+ range => "1:30 - 4:30",
}
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.
+ EOT
# This is lame; properties all use arrays as values, but parameters don't.
# That's going to hurt eventually.
validate do |values|
values = [values] unless values.is_a?(Array)
values.each { |value|
unless value.is_a?(String) and
value =~ /\d+(:\d+){0,2}\s*-\s*\d+(:\d+){0,2}/
self.fail "Invalid range value '#{value}'"
end
}
end
munge do |values|
values = [values] unless values.is_a?(Array)
ret = []
values.each { |value|
range = []
# Split each range value into a hour, minute, second triad
value.split(/\s*-\s*/).each { |val|
# Add the values as an array.
range << val.split(":").collect { |n| n.to_i }
}
self.fail "Invalid range #{value}" if range.length != 2
# Make sure the hours are valid
[range[0][0], range[1][0]].each do |n|
raise ArgumentError, "Invalid hour '#{n}'" if n < 0 or n > 23
end
[range[0][1], range[1][1]].each do |n|
raise ArgumentError, "Invalid minute '#{n}'" if n and (n < 0 or n > 59)
end
if range[0][0] > range[1][0]
self.fail(("Invalid range #{value}; ") +
"ranges cannot span days."
)
end
ret << range
}
# Now our array of arrays
ret
end
def match?(previous, now)
# The lowest-level array is of the hour, minute, second triad
# then it's an array of two of those, to present the limits
# then it's array of those ranges
@value = [@value] unless @value[0][0].is_a?(Array)
@value.each do |value|
limits = value.collect do |range|
ary = [now.year, now.month, now.day, range[0]]
if range[1]
ary << range[1]
else
ary << now.min
end
if range[2]
ary << range[2]
else
ary << now.sec
end
time = Time.local(*ary)
unless time.hour == range[0]
self.devfail(
"Incorrectly converted time: #{time}: #{time.hour} vs #{range[0]}"
)
end
time
end
unless limits[0] < limits[1]
self.info(
"Assuming upper limit should be that time the next day"
)
ary = limits[1].to_a
ary[3] += 1
limits[1] = Time.local(*ary)
#self.devfail("Lower limit is above higher limit: %s" %
# limits.inspect
#)
end
#self.info limits.inspect
#self.notice now
return now.between?(*limits)
end
# Else, return false, since our current time isn't between
# any valid times
false
end
end
newparam(:periodmatch) do
desc "Whether periods should be matched by number (e.g., the two times
are in the same hour) or by distance (e.g., the two times are
60 minutes apart)."
newvalues(:number, :distance)
defaultto :distance
end
newparam(:period) do
- desc "The period of repetition for a resource. Choose from among
- a fixed list of *hourly*, *daily*, *weekly*, and *monthly*.
- The default is for a resource to get applied every time that
- Puppet runs, whatever that period is.
+ desc <<-EOT
+ The period of repetition for a resource. The default is for a resource
+ to get applied every time Puppet runs.
Note that the period defines how often a given resource will get
applied but not when; if you would like to restrict the hours
that a given resource can be applied (e.g., only at night during
- a maintenance window) then use the `range` attribute.
+ a maintenance window), then use the `range` attribute.
If the provided periods are not sufficient, you can provide a
value to the *repeat* attribute, which will cause Puppet to
schedule the affected resources evenly in the period the
specified number of times. Take this schedule:
- schedule { veryoften:
+ schedule { 'veryoften':
period => hourly,
- repeat => 6
+ repeat => 6,
}
This can cause Puppet to apply that resource up to every 10 minutes.
At the moment, Puppet cannot guarantee that level of
repetition; that is, it can run up to every 10 minutes, but
internal factors might prevent it from actually running that
often (e.g., long-running Puppet runs will squash conflictingly scheduled runs).
See the `periodmatch` attribute for tuning whether to match
- times by their distance apart or by their specific value."
+ times by their distance apart or by their specific value.
+ EOT
newvalues(:hourly, :daily, :weekly, :monthly, :never)
@@scale = {
:hourly => 3600,
:daily => 86400,
:weekly => 604800,
:monthly => 2592000
}
@@methods = {
:hourly => :hour,
:daily => :day,
:monthly => :month,
:weekly => proc do |prev, now|
# Run the resource if the previous day was after this weekday (e.g., prev is wed, current is tue)
# or if it's been more than a week since we ran
prev.wday > now.wday or (now - prev) > (24 * 3600 * 7)
end
}
def match?(previous, now)
return false if value == :never
value = self.value
case @resource[:periodmatch]
when :number
method = @@methods[value]
if method.is_a?(Proc)
return method.call(previous, now)
else
# We negate it, because if they're equal we don't run
return now.send(method) != previous.send(method)
end
when :distance
scale = @@scale[value]
# If the number of seconds between the two times is greater
# than the unit of time, we match. We divide the scale
# by the repeat, so that we'll repeat that often within
# the scale.
diff = (now.to_i - previous.to_i)
comparison = (scale / @resource[:repeat])
return (now.to_i - previous.to_i) >= (scale / @resource[:repeat])
end
end
end
newparam(:repeat) do
- desc "How often the application gets repeated in a given period.
- Defaults to 1. Must be an integer."
+ desc "How often a given resource may be applied in this schedule's `period`.
+ Defaults to 1; must be an integer."
defaultto 1
validate do |value|
unless value.is_a?(Integer) or value =~ /^\d+$/
raise Puppet::Error,
"Repeat must be a number"
end
# This implicitly assumes that 'periodmatch' is distance -- that
# is, if there's no value, we assume it's a valid value.
return unless @resource[:periodmatch]
if value != 1 and @resource[:periodmatch] != :distance
raise Puppet::Error,
"Repeat must be 1 unless periodmatch is 'distance', not '#{@resource[:periodmatch]}'"
end
end
munge do |value|
value = Integer(value) unless value.is_a?(Integer)
value
end
def match?(previous, now)
true
end
end
def self.instances
[]
end
def self.mkdefaultschedules
result = []
Puppet.debug "Creating default schedules"
result << self.new(
:name => "puppet",
:period => :hourly,
:repeat => "2"
)
# And then one for every period
@parameters.find { |p| p.name == :period }.value_collection.values.each { |value|
result << self.new(
:name => value.to_s,
:period => value
)
}
result
end
def match?(previous = nil, now = nil)
# If we've got a value, then convert it to a Time instance
previous &&= Time.at(previous)
now ||= Time.now
# Pull them in order
self.class.allattrs.each { |param|
if @parameters.include?(param) and
@parameters[param].respond_to?(:match?)
return false unless @parameters[param].match?(previous, now)
end
}
# If we haven't returned false, then return true; in other words,
# any provided schedules need to all match
true
end
end
end
diff --git a/lib/puppet/type/selmodule.rb b/lib/puppet/type/selmodule.rb
index e76c18cc0..a2c467736 100644
--- a/lib/puppet/type/selmodule.rb
+++ b/lib/puppet/type/selmodule.rb
@@ -1,55 +1,59 @@
#
# Simple module for manageing SELinux policy modules
#
Puppet::Type.newtype(:selmodule) do
@doc = "Manages loading and unloading of SELinux policy modules
on the system. Requires SELinux support. See man semodule(8)
for more information on SELinux policy modules.
-
- **Autorequires:** If Puppet is managing the file containing this SELinux policy module (which is either explicitly specified in the `selmodulepath` attribute or will be found at {`selmoduledir`}/{`name`}.pp), the selmodule resource will autorequire that file."
+
+ **Autorequires:** If Puppet is managing the file containing this SELinux
+ policy module (which is either explicitly specified in the `selmodulepath`
+ attribute or will be found at {`selmoduledir`}/{`name`}.pp), the selmodule
+ resource will autorequire that file."
ensurable
newparam(:name) do
desc "The name of the SELinux policy to be managed. You should not
include the customary trailing .pp extension."
isnamevar
end
newparam(:selmoduledir) do
desc "The directory to look for the compiled pp module file in.
- Currently defaults to `/usr/share/selinux/targeted`. If selmodulepath
- is not specified the module will be looked for in this directory in a
- in a file called NAME.pp, where NAME is the value of the name parameter."
+ Currently defaults to `/usr/share/selinux/targeted`. If the
+ `selmodulepath` attribute is not specified, Puppet will expect to find
+ the module in `<selmoduledir>/<name>.pp`, where `name` is the value of the
+ `name` parameter."
defaultto "/usr/share/selinux/targeted"
end
newparam(:selmodulepath) do
desc "The full path to the compiled .pp policy module. You only need to use
- this if the module file is not in the directory pointed at by selmoduledir."
+ this if the module file is not in the `selmoduledir` directory."
end
newproperty(:syncversion) do
desc "If set to `true`, the policy will be reloaded if the
version found in the on-disk file differs from the loaded
version. If set to `false` (the default) the the only check
that will be made is if the policy is loaded at all or not."
newvalue(:true)
newvalue(:false)
end
autorequire(:file) do
if self[:selmodulepath]
[self[:selmodulepath]]
else
["#{self[:selmoduledir]}/#{self[:name]}.pp"]
end
end
end
diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb
index 6a5b273c1..2a89f667a 100644
--- a/lib/puppet/type/service.rb
+++ b/lib/puppet/type/service.rb
@@ -1,207 +1,207 @@
# This is our main way of managing processes right now.
#
# a service is distinct from a process in that services
# can only be managed through the interface of an init script
# which is why they have a search path for initscripts and such
module Puppet
newtype(:service) do
@doc = "Manage running services. Service support unfortunately varies
widely by platform --- some platforms have very little if any concept of a
running service, and some have a very codified and powerful concept.
Puppet's service support is usually capable of doing the right thing, but
the more information you can provide, the better behaviour you will get.
Puppet 2.7 and newer expect init scripts to have a working status command.
If this isn't the case for any of your services' init scripts, you will
need to set `hasstatus` to false and possibly specify a custom status
command in the `status` attribute.
Note that if a `service` receives an event from another resource,
the service will get restarted. The actual command to restart the
- service depends on the platform. You can provide an explicit command
- for restarting with the `restart` attribute, or use the init script's
- restart command with the `hasrestart` attribute; if you do neither,
- the service's stop and start commands will be used."
+ service depends on the platform. You can provide an explicit command for
+ restarting with the `restart` attribute, or you can set `hasrestart` to
+ true to use the init script's restart command; if you do neither, the
+ service's stop and start commands will be used."
feature :refreshable, "The provider can restart the service.",
:methods => [:restart]
feature :enableable, "The provider can enable and disable the service",
:methods => [:disable, :enable, :enabled?]
feature :controllable, "The provider uses a control variable."
newproperty(:enable, :required_features => :enableable) do
desc "Whether a service should be enabled to start at boot.
This property behaves quite differently depending on the platform;
wherever possible, it relies on local tools to enable or disable
a given service."
newvalue(:true, :event => :service_enabled) do
provider.enable
end
newvalue(:false, :event => :service_disabled) do
provider.disable
end
newvalue(:manual, :event => :service_manual_start) do
provider.manual_start
end
def retrieve
provider.enabled?
end
validate do |value|
if value == :manual and !Puppet.features.microsoft_windows?
raise Puppet::Error.new("Setting enable to manual is only supported on Microsoft Windows.")
end
end
end
# Handle whether the service should actually be running right now.
newproperty(:ensure) do
desc "Whether a service should be running."
newvalue(:stopped, :event => :service_stopped) do
provider.stop
end
newvalue(:running, :event => :service_started) do
provider.start
end
aliasvalue(:false, :stopped)
aliasvalue(:true, :running)
def retrieve
provider.status
end
def sync
event = super()
if property = @resource.property(:enable)
val = property.retrieve
property.sync unless property.safe_insync?(val)
end
event
end
end
newparam(:binary) do
desc "The path to the daemon. This is only used for
systems that do not support init scripts. This binary will be
used to start the service if no `start` parameter is
provided."
end
newparam(:hasstatus) do
desc "Declare whether the service's init script has a functional status
command; defaults to `true`. This attribute's default value changed in
Puppet 2.7.0.
If a service's init script does not support any kind of status command,
you should set `hasstatus` to false and either provide a specific
command using the `status` attribute or expect that Puppet will look for
the service name in the process table. Be aware that 'virtual' init
scripts (like 'network' under Red Hat systems) will respond poorly to
refresh events from other resources if you override the default behavior
without providing a status command."
newvalues(:true, :false)
defaultto :true
end
newparam(:name) do
desc "The name of the service to run. This name is used to find
the service in whatever service subsystem it is in."
isnamevar
end
newparam(:path) do
desc "The search path for finding init scripts. Multiple values should
be separated by colons or provided as an array."
munge do |value|
value = [value] unless value.is_a?(Array)
# LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
# It affects stand-alone blocks, too.
paths = value.flatten.collect { |p| x = p.split(File::PATH_SEPARATOR) }.flatten
end
defaultto { provider.class.defpath if provider.class.respond_to?(:defpath) }
end
newparam(:pattern) do
desc "The pattern to search for in the process table.
This is used for stopping services on platforms that do not
support init scripts, and is also used for determining service
status on those service whose init scripts do not include a status
command.
- If this is left unspecified and is needed to check the status
- of a service, then the service name will be used instead.
-
- The pattern can be a simple string or any legal Ruby pattern."
+ Defaults to the name of the service. The pattern can be a simple string
+ or any legal Ruby pattern."
defaultto { @resource[:binary] || @resource[:name] }
end
newparam(:restart) do
desc "Specify a *restart* command manually. If left
unspecified, the service will be stopped and then started."
end
newparam(:start) do
desc "Specify a *start* command manually. Most service subsystems
support a `start` command, so this will not need to be
specified."
end
newparam(:status) do
desc "Specify a *status* command manually. This command must
return 0 if the service is running and a nonzero value otherwise.
Ideally, these return codes should conform to
[the LSB's specification for init script status actions](http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html),
- but puppet only considers the difference between 0 and nonzero
+ but Puppet only considers the difference between 0 and nonzero
to be relevant.
If left unspecified, the status method will be determined
automatically, usually by looking for the service in the process
table."
end
newparam(:stop) do
desc "Specify a *stop* command manually."
end
newparam(:control) do
desc "The control variable used to manage services (originally for HP-UX).
Defaults to the upcased service name plus `START` replacing dots with
underscores, for those providers that support the `controllable` feature."
defaultto { resource.name.gsub(".","_").upcase + "_START" if resource.provider.controllable? }
end
newparam :hasrestart do
- desc "Specify that an init script has a `restart` option. Otherwise,
- the init script's `stop` and `start` methods are used."
+ desc "Specify that an init script has a `restart` command. If this is
+ false and you do not specify a command in the `restart` attribute,
+ the init script's `stop` and `start` commands will be used. Defaults
+ to true; note that this is a change from earlier versions of Puppet."
newvalues(:true, :false)
end
newparam(:manifest) do
desc "Specify a command to config a service, or a path to a manifest to do so."
end
# Basically just a synonym for restarting. Used to respond
# to events.
def refresh
# Only restart if we're actually running
if (@parameters[:ensure] || newattr(:ensure)).retrieve == :running
provider.restart
else
debug "Skipping restart; service is not running"
end
end
end
end
diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb
index 59a1a12f8..d8c4020ec 100755
--- a/lib/puppet/type/sshkey.rb
+++ b/lib/puppet/type/sshkey.rb
@@ -1,72 +1,72 @@
module Puppet
newtype(:sshkey) do
@doc = "Installs and manages ssh host keys. At this point, this type
- only knows how to install keys into `/etc/ssh/ssh_known_hosts`. See
+ only knows how to install keys into `/etc/ssh/ssh_known_hosts`. See
the `ssh_authorized_key` type to manage authorized keys."
ensurable
newproperty(:type) do
desc "The encryption type used. Probably ssh-dss or ssh-rsa."
newvalue("ssh-dss")
newvalue("ssh-rsa")
aliasvalue(:dsa, "ssh-dss")
aliasvalue(:rsa, "ssh-rsa")
end
newproperty(:key) do
desc "The key itself; generally a long string of hex digits."
end
# FIXME This should automagically check for aliases to the hosts, just
# to see if we can automatically glean any aliases.
newproperty(:host_aliases) do
desc 'Any aliases the host might have. Multiple values must be
specified as an array.'
attr_accessor :meta
def insync?(is)
is == @should
end
# We actually want to return the whole array here, not just the first
# value.
def should
defined?(@should) ? @should : nil
end
validate do |value|
if value =~ /\s/
raise Puppet::Error, "Aliases cannot include whitespace"
end
if value =~ /,/
raise Puppet::Error, "Aliases must be provided as an array, not a comma-separated list"
end
end
end
newparam(:name) do
desc "The host name that the key is associated with."
isnamevar
validate do |value|
raise Puppet::Error, "Resourcename cannot include whitespaces" if value =~ /\s/
raise Puppet::Error, "No comma in resourcename allowed. If you want to specify aliases use the host_aliases property" if value.include?(',')
end
end
newproperty(:target) do
desc "The file in which to store the ssh key. Only used by
the `parsed` provider."
defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
@resource.class.defaultprovider.default_target
else
nil
end
}
end
end
end
diff --git a/lib/puppet/type/stage.rb b/lib/puppet/type/stage.rb
index 0736dc4b9..6156be256 100644
--- a/lib/puppet/type/stage.rb
+++ b/lib/puppet/type/stage.rb
@@ -1,19 +1,19 @@
Puppet::Type.newtype(:stage) do
desc "A resource type for specifying run stages. The actual stage should
be specified on resources:
-
+
class { foo: stage => pre }
And you must manually control stage order:
stage { pre: before => Stage[main] }
You automatically get a 'main' stage created, and by default all resources
get inserted into that stage.
You can only set stages on class resources, not normal builtin resources."
newparam :name do
desc "The name of the stage. This will be used as the 'stage' for each resource."
end
end
diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb
index 1a308e17d..224e79731 100755
--- a/lib/puppet/type/tidy.rb
+++ b/lib/puppet/type/tidy.rb
@@ -1,331 +1,333 @@
Puppet::Type.newtype(:tidy) do
require 'puppet/file_serving/fileset'
require 'puppet/file_bucket/dipper'
@doc = "Remove unwanted files based on specific criteria. Multiple
criteria are OR'd together, so a file that is too large but is not
old enough will still get tidied.
If you don't specify either `age` or `size`, then all files will
be removed.
This resource type works by generating a file resource for every file
that should be deleted and then letting that resource perform the
actual deletion.
"
newparam(:path) do
desc "The path to the file or directory to manage. Must be fully
qualified."
isnamevar
end
newparam(:recurse) do
desc "If target is a directory, recursively descend
into the directory looking for files to tidy."
newvalues(:true, :false, :inf, /^[0-9]+$/)
# Replace the validation so that we allow numbers in
# addition to string representations of them.
validate { |arg| }
munge do |value|
newval = super(value)
case newval
when :true, :inf; true
when :false; false
when Integer, Fixnum, Bignum; value
when /^\d+$/; Integer(value)
else
raise ArgumentError, "Invalid recurse value #{value.inspect}"
end
end
end
newparam(:matches) do
- desc "One or more (shell type) file glob patterns, which restrict
+ desc <<-EOT
+ One or more (shell type) file glob patterns, which restrict
the list of files to be tidied to those whose basenames match
at least one of the patterns specified. Multiple patterns can
be specified using an array.
Example:
- tidy { \"/tmp\":
- age => \"1w\",
+ tidy { "/tmp":
+ age => "1w",
recurse => 1,
- matches => [ \"[0-9]pub*.tmp\", \"*.temp\", \"tmpfile?\" ]
+ matches => [ "[0-9]pub*.tmp", "*.temp", "tmpfile?" ]
}
This removes files from `/tmp` if they are one week old or older,
are not in a subdirectory and match one of the shell globs given.
Note that the patterns are matched against the basename of each
file -- that is, your glob patterns should not have any '/'
characters in them, since you are only specifying against the last
bit of the file.
Finally, note that you must now specify a non-zero/non-false value
for recurse if matches is used, as matches only apply to files found
by recursion (there's no reason to use static patterns match against
a statically determined path). Requiering explicit recursion clears
- up a common source of confusion."
+ up a common source of confusion.
+ EOT
# Make sure we convert to an array.
munge do |value|
fail "Tidy can't use matches with recurse 0, false, or undef" if "#{@resource[:recurse]}" =~ /^(0|false|)$/
[value].flatten
end
# Does a given path match our glob patterns, if any? Return true
# if no patterns have been provided.
def tidy?(path, stat)
basename = File.basename(path)
flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
return(value.find {|pattern| File.fnmatch(pattern, basename, flags) } ? true : false)
end
end
newparam(:backup) do
desc "Whether tidied files should be backed up. Any values are passed
- directly to the file resources used for actual file deletion, so use
- its backup documentation to determine valid values."
+ directly to the file resources used for actual file deletion, so consult
+ the `file` type's backup documentation to determine valid values."
end
newparam(:age) do
desc "Tidy files whose age is equal to or greater than
the specified time. You can choose seconds, minutes,
hours, days, or weeks by specifying the first letter of any
of those words (e.g., '1w').
Specifying 0 will remove all files."
@@ageconvertors = {
:s => 1,
:m => 60
}
@@ageconvertors[:h] = @@ageconvertors[:m] * 60
@@ageconvertors[:d] = @@ageconvertors[:h] * 24
@@ageconvertors[:w] = @@ageconvertors[:d] * 7
def convert(unit, multi)
if num = @@ageconvertors[unit]
return num * multi
else
self.fail "Invalid age unit '#{unit}'"
end
end
def tidy?(path, stat)
# If the file's older than we allow, we should get rid of it.
(Time.now.to_i - stat.send(resource[:type]).to_i) > value
end
munge do |age|
unit = multi = nil
case age
when /^([0-9]+)(\w)\w*$/
multi = Integer($1)
unit = $2.downcase.intern
when /^([0-9]+)$/
multi = Integer($1)
unit = :d
else
self.fail "Invalid tidy age #{age}"
end
convert(unit, multi)
end
end
newparam(:size) do
desc "Tidy files whose size is equal to or greater than
the specified size. Unqualified values are in kilobytes, but
*b*, *k*, *m*, *g*, and *t* can be appended to specify *bytes*,
*kilobytes*, *megabytes*, *gigabytes*, and *terabytes*, respectively.
- Only the first character is significant, so the full word can also
+ Only the first character is significant, so the full word can also
be used."
@@sizeconvertors = {
:b => 0,
:k => 1,
:m => 2,
:g => 3,
:t => 4
}
def convert(unit, multi)
if num = @@sizeconvertors[unit]
result = multi
num.times do result *= 1024 end
return result
else
self.fail "Invalid size unit '#{unit}'"
end
end
def tidy?(path, stat)
stat.size >= value
end
munge do |size|
case size
when /^([0-9]+)(\w)\w*$/
multi = Integer($1)
unit = $2.downcase.intern
when /^([0-9]+)$/
multi = Integer($1)
unit = :k
else
self.fail "Invalid tidy size #{age}"
end
convert(unit, multi)
end
end
newparam(:type) do
desc "Set the mechanism for determining age."
newvalues(:atime, :mtime, :ctime)
defaultto :atime
end
newparam(:rmdirs, :boolean => true) do
desc "Tidy directories in addition to files; that is, remove
directories whose age is older than the specified criteria.
This will only remove empty directories, so all contained
files must also be tidied before a directory gets removed."
newvalues :true, :false
end
# Erase PFile's validate method
validate do
end
def self.instances
[]
end
def depthfirst?
true
end
def initialize(hash)
super
# only allow backing up into filebuckets
self[:backup] = false unless self[:backup].is_a? Puppet::FileBucket::Dipper
end
# Make a file resource to remove a given file.
def mkfile(path)
# Force deletion, so directories actually get deleted.
Puppet::Type.type(:file).new :path => path, :backup => self[:backup], :ensure => :absent, :force => true
end
def retrieve
# Our ensure property knows how to retrieve everything for us.
if obj = @parameters[:ensure]
return obj.retrieve
else
return {}
end
end
# Hack things a bit so we only ever check the ensure property.
def properties
[]
end
def generate
return [] unless stat(self[:path])
case self[:recurse]
when Integer, Fixnum, Bignum, /^\d+$/
parameter = { :recurse => true, :recurselimit => self[:recurse] }
when true, :true, :inf
parameter = { :recurse => true }
end
if parameter
files = Puppet::FileServing::Fileset.new(self[:path], parameter).files.collect do |f|
f == "." ? self[:path] : ::File.join(self[:path], f)
end
else
files = [self[:path]]
end
result = files.find_all { |path| tidy?(path) }.collect { |path| mkfile(path) }.each { |file| notice "Tidying #{file.ref}" }.sort { |a,b| b[:path] <=> a[:path] }
# No need to worry about relationships if we don't have rmdirs; there won't be
# any directories.
return result unless rmdirs?
# Now make sure that all directories require the files they contain, if all are available,
# so that a directory is emptied before we try to remove it.
files_by_name = result.inject({}) { |hash, file| hash[file[:path]] = file; hash }
files_by_name.keys.sort { |a,b| b <=> b }.each do |path|
dir = ::File.dirname(path)
next unless resource = files_by_name[dir]
if resource[:require]
resource[:require] << Puppet::Resource.new(:file, path)
else
resource[:require] = [Puppet::Resource.new(:file, path)]
end
end
result
end
# Does a given path match our glob patterns, if any? Return true
# if no patterns have been provided.
def matches?(path)
return true unless self[:matches]
basename = File.basename(path)
flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
if self[:matches].find {|pattern| File.fnmatch(pattern, basename, flags) }
return true
else
debug "No specified patterns match #{path}, not tidying"
return false
end
end
# Should we remove the specified file?
def tidy?(path)
return false unless stat = self.stat(path)
return false if stat.ftype == "directory" and ! rmdirs?
# The 'matches' parameter isn't OR'ed with the other tests --
# it's just used to reduce the list of files we can match.
return false if param = parameter(:matches) and ! param.tidy?(path, stat)
tested = false
[:age, :size].each do |name|
next unless param = parameter(name)
tested = true
return true if param.tidy?(path, stat)
end
# If they don't specify either, then the file should always be removed.
return true unless tested
false
end
def stat(path)
begin
::File.lstat(path)
rescue Errno::ENOENT => error
info "File does not exist"
return nil
rescue Errno::EACCES => error
warning "Could not stat; permission denied"
return nil
end
end
end
diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb
index ea23378ed..71c208002 100755
--- a/lib/puppet/type/user.rb
+++ b/lib/puppet/type/user.rb
@@ -1,495 +1,503 @@
require 'etc'
require 'facter'
require 'puppet/property/list'
require 'puppet/property/ordered_list'
require 'puppet/property/keyvalue'
module Puppet
newtype(:user) do
@doc = "Manage users. This type is mostly built to manage system
users, so it is lacking some features useful for managing normal
users.
This resource type uses the prescribed native tools for creating
groups and generally uses POSIX APIs for retrieving information
about them. It does not directly modify `/etc/passwd` or anything.
- **Autorequires:** If Puppet is managing the user's primary group (as provided in the `gid` attribute), the user resource will autorequire that group. If Puppet is managing any role accounts corresponding to the user's roles, the user resource will autorequire those role accounts."
+ **Autorequires:** If Puppet is managing the user's primary group (as
+ provided in the `gid` attribute), the user resource will autorequire
+ that group. If Puppet is managing any role accounts corresponding to the
+ user's roles, the user resource will autorequire those role accounts."
feature :allows_duplicates,
"The provider supports duplicate users with the same UID."
feature :manages_homedir,
"The provider can create and remove home directories."
feature :manages_passwords,
"The provider can modify user passwords, by accepting a password
hash."
feature :manages_password_age,
"The provider can set age requirements and restrictions for
passwords."
feature :manages_solaris_rbac,
"The provider can manage roles and normal users"
feature :manages_expiry,
"The provider can manage the expiry date for a user."
feature :system_users,
"The provider allows you to create system users with lower UIDs."
feature :manages_aix_lam,
"The provider can manage AIX Loadable Authentication Module (LAM) system."
newproperty(:ensure, :parent => Puppet::Property::Ensure) do
newvalue(:present, :event => :user_created) do
provider.create
end
newvalue(:absent, :event => :user_removed) do
provider.delete
end
newvalue(:role, :event => :role_created, :required_features => :manages_solaris_rbac) do
provider.create_role
end
desc "The basic state that the object should be in."
# If they're talking about the thing at all, they generally want to
# say it should exist.
defaultto do
if @resource.managed?
:present
else
nil
end
end
def retrieve
if provider.exists?
if provider.respond_to?(:is_role?) and provider.is_role?
return :role
else
return :present
end
else
return :absent
end
end
end
newproperty(:home) do
desc "The home directory of the user. The directory must be created
separately and is not currently checked for existence."
end
newproperty(:uid) do
- desc "The user ID. Must be specified numerically. For new users
- being created, if no user ID is specified then one will be
- chosen automatically, which will likely result in the same user
- having different IDs on different systems, which is not
- recommended. This is especially noteworthy if you use Puppet
- to manage the same user on both Darwin and other platforms,
- since Puppet does the ID generation for you on Darwin, but the
- tools do so on other platforms.
-
- On Windows, the property will return the user's security
- identifier (SID)."
+ desc "The user ID; must be specified numerically. If no user ID is
+ specified when creating a new user, then one will be chosen
+ automatically. This will likely result in the same user having
+ different UIDs on different systems, which is not recommended. This is
+ especially noteworthy when managing the same user on both Darwin and
+ other platforms, since Puppet does UID generation on Darwin, but
+ the underlying tools do so on other platforms.
+
+ On Windows, this property is read-only and will return the user's
+ security identifier (SID)."
munge do |value|
case value
when String
if value =~ /^[-0-9]+$/
value = Integer(value)
end
end
return value
end
end
newproperty(:gid) do
desc "The user's primary group. Can be specified numerically or
by name."
munge do |value|
if value.is_a?(String) and value =~ /^[-0-9]+$/
Integer(value)
else
value
end
end
def insync?(is)
# We know the 'is' is a number, so we need to convert the 'should' to a number,
# too.
@should.each do |value|
return true if number = Puppet::Util.gid(value) and is == number
end
false
end
def sync
found = false
@should.each do |value|
if number = Puppet::Util.gid(value)
provider.gid = number
found = true
break
end
end
fail "Could not find group(s) #{@should.join(",")}" unless found
# Use the default event.
end
end
newproperty(:comment) do
- desc "A description of the user. Generally is a user's full name."
+ desc "A description of the user. Generally the user's full name."
end
newproperty(:shell) do
desc "The user's login shell. The shell must exist and be
executable."
end
newproperty(:password, :required_features => :manages_passwords) do
- desc "The user's password, in whatever encrypted format the local machine requires. Be sure to enclose any value that includes a dollar sign ($) in single quotes (\')."
+ desc %q{The user's password, in whatever encrypted format the local
+ machine requires. Be sure to enclose any value that includes a dollar
+ sign ($) in single quotes (') to avoid accidental variable
+ interpolation.}
validate do |value|
raise ArgumentError, "Passwords cannot include ':'" if value.is_a?(String) and value.include?(":")
end
def change_to_s(currentvalue, newvalue)
if currentvalue == :absent
return "created password"
else
return "changed password"
end
end
def is_to_s( currentvalue )
return '[old password hash redacted]'
end
def should_to_s( newvalue )
return '[new password hash redacted]'
end
end
newproperty(:password_min_age, :required_features => :manages_password_age) do
- desc "The minimum amount of time in days a password must be used before it may be changed"
+ desc "The minimum number of days a password must be used before it may be changed."
munge do |value|
case value
when String
Integer(value)
else
value
end
end
validate do |value|
if value.to_s !~ /^-?\d+$/
- raise ArgumentError, "Password minimum age must be provided as a number"
+ raise ArgumentError, "Password minimum age must be provided as a number."
end
end
end
newproperty(:password_max_age, :required_features => :manages_password_age) do
- desc "The maximum amount of time in days a password may be used before it must be changed"
+ desc "The maximum number of days a password may be used before it must be changed."
munge do |value|
case value
when String
Integer(value)
else
value
end
end
validate do |value|
if value.to_s !~ /^-?\d+$/
- raise ArgumentError, "Password maximum age must be provided as a number"
+ raise ArgumentError, "Password maximum age must be provided as a number."
end
end
end
newproperty(:groups, :parent => Puppet::Property::List) do
- desc "The groups of which the user is a member. The primary
- group should not be listed. Multiple groups should be
- specified as an array."
+ desc "The groups to which the user belongs. The primary group should
+ not be listed, and groups should be identified by name rather than by
+ GID. Multiple groups should be specified as an array."
validate do |value|
if value =~ /^\d+$/
- raise ArgumentError, "Group names must be provided, not numbers"
+ raise ArgumentError, "Group names must be provided, not GID numbers."
end
- raise ArgumentError, "Group names must be provided as an array, not a comma-separated list" if value.include?(",")
+ raise ArgumentError, "Group names must be provided as an array, not a comma-separated list." if value.include?(",")
end
end
newparam(:name) do
- desc "User name. While limitations are determined for
- each operating system, it is generally a good idea to keep to
- the degenerate 8 characters, beginning with a letter."
+ desc "The user name. While naming limitations vary by operating system,
+ it is advisable to restrict names to the lowest common denominator,
+ which is a maximum of 8 characters beginning with a letter."
isnamevar
end
newparam(:membership) do
- desc "Whether specified groups should be treated as the only groups
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ desc "Whether specified groups should be considered the **complete list**
+ (`inclusive`) or the **minimum list** (`minimum`) of groups to which
+ the user belongs. Defaults to `minimum`."
newvalues(:inclusive, :minimum)
defaultto :minimum
end
newparam(:system, :boolean => true) do
- desc "Whether the user is a system user with lower UID."
+ desc "Whether the user is a system user, according to the OS's criteria;
+ on most platforms, a UID less than or equal to 500 indicates a system
+ user. Defaults to `false`."
newvalues(:true, :false)
defaultto false
end
newparam(:allowdupe, :boolean => true) do
- desc "Whether to allow duplicate UIDs."
+ desc "Whether to allow duplicate UIDs. Defaults to `false`."
newvalues(:true, :false)
defaultto false
end
newparam(:managehome, :boolean => true) do
- desc "Whether to manage the home directory when managing the user."
+ desc "Whether to manage the home directory when managing the user.
+ Defaults to `false`."
newvalues(:true, :false)
defaultto false
validate do |val|
if val.to_s == "true"
raise ArgumentError, "User provider #{provider.class.name} can not manage home directories" unless provider.class.manages_homedir?
end
end
end
newproperty(:expiry, :required_features => :manages_expiry) do
desc "The expiry date for this user. Must be provided in
- a zero padded YYYY-MM-DD format - e.g 2010-02-19."
+ a zero-padded YYYY-MM-DD format --- e.g. 2010-02-19."
validate do |value|
if value !~ /^\d{4}-\d{2}-\d{2}$/
raise ArgumentError, "Expiry dates must be YYYY-MM-DD"
end
end
end
# Autorequire the group, if it's around
autorequire(:group) do
autos = []
if obj = @parameters[:gid] and groups = obj.shouldorig
groups = groups.collect { |group|
if group =~ /^\d+$/
Integer(group)
else
group
end
}
groups.each { |group|
case group
when Integer
if resource = catalog.resources.find { |r| r.is_a?(Puppet::Type.type(:group)) and r.should(:gid) == group }
autos << resource
end
else
autos << group
end
}
end
if obj = @parameters[:groups] and groups = obj.should
autos += groups.split(",")
end
autos
end
# Provide an external hook. Yay breaking out of APIs.
def exists?
provider.exists?
end
def retrieve
absent = false
properties.inject({}) { |prophash, property|
current_value = :absent
if absent
prophash[property] = :absent
else
current_value = property.retrieve
prophash[property] = current_value
end
if property.name == :ensure and current_value == :absent
absent = true
end
prophash
}
end
newproperty(:roles, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
desc "The roles the user has. Multiple roles should be
specified as an array."
def membership
:role_membership
end
validate do |value|
if value =~ /^\d+$/
raise ArgumentError, "Role names must be provided, not numbers"
end
raise ArgumentError, "Role names must be provided as an array, not a comma-separated list" if value.include?(",")
end
end
#autorequire the roles that the user has
autorequire(:user) do
reqs = []
if roles_property = @parameters[:roles] and roles = roles_property.should
reqs += roles.split(',')
end
reqs
end
newparam(:role_membership) do
- desc "Whether specified roles should be treated as the only roles
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ desc "Whether specified roles should be considered the **complete list**
+ (`inclusive`) or the **minimum list** (`minimum`) of roles the user
+ has. Defaults to `minimum`."
newvalues(:inclusive, :minimum)
defaultto :minimum
end
newproperty(:auths, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
desc "The auths the user has. Multiple auths should be
specified as an array."
def membership
:auth_membership
end
validate do |value|
if value =~ /^\d+$/
raise ArgumentError, "Auth names must be provided, not numbers"
end
raise ArgumentError, "Auth names must be provided as an array, not a comma-separated list" if value.include?(",")
end
end
newparam(:auth_membership) do
- desc "Whether specified auths should be treated as the only auths
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ desc "Whether specified auths should be considered the **complete list**
+ (`inclusive`) or the **minimum list** (`minimum`) of auths the user
+ has. Defaults to `minimum`."
newvalues(:inclusive, :minimum)
defaultto :minimum
end
newproperty(:profiles, :parent => Puppet::Property::OrderedList, :required_features => :manages_solaris_rbac) do
desc "The profiles the user has. Multiple profiles should be
specified as an array."
def membership
:profile_membership
end
validate do |value|
if value =~ /^\d+$/
raise ArgumentError, "Profile names must be provided, not numbers"
end
raise ArgumentError, "Profile names must be provided as an array, not a comma-separated list" if value.include?(",")
end
end
newparam(:profile_membership) do
- desc "Whether specified roles should be treated as the only roles
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ desc "Whether specified roles should be treated as the **complete list**
+ (`inclusive`) or the **minimum list** (`minimum`) of roles
+ of which the user is a member. Defaults to `minimum`."
newvalues(:inclusive, :minimum)
defaultto :minimum
end
newproperty(:keys, :parent => Puppet::Property::KeyValue, :required_features => :manages_solaris_rbac) do
- desc "Specify user attributes in an array of keyvalue pairs"
+ desc "Specify user attributes in an array of key = value pairs."
def membership
:key_membership
end
validate do |value|
- raise ArgumentError, "key value pairs must be seperated by an =" unless value.include?("=")
+ raise ArgumentError, "Key/value pairs must be seperated by an =" unless value.include?("=")
end
end
newparam(:key_membership) do
- desc "Whether specified key value pairs should be treated as the only attributes
- of the user or whether they should merely
- be treated as the minimum list."
+ desc "Whether specified key/value pairs should be considered the
+ **complete list** (`inclusive`) or the **minimum list** (`minimum`) of
+ the user's attributes. Defaults to `minimum`."
newvalues(:inclusive, :minimum)
defaultto :minimum
end
newproperty(:project, :required_features => :manages_solaris_rbac) do
- desc "The name of the project associated with a user"
+ desc "The name of the project associated with a user."
end
newparam(:ia_load_module, :required_features => :manages_aix_lam) do
- desc "The name of the I&A module to use to manage this user"
+ desc "The name of the I&A module to use to manage this user."
end
newproperty(:attributes, :parent => Puppet::Property::KeyValue, :required_features => :manages_aix_lam) do
- desc "Specify user AIX attributes in an array of keyvalue pairs"
+ desc "Specify AIX attributes for the user in an array of attribute = value pairs."
def membership
:attribute_membership
end
def delimiter
" "
end
validate do |value|
raise ArgumentError, "Attributes value pairs must be seperated by an =" unless value.include?("=")
end
end
newparam(:attribute_membership) do
- desc "Whether specified attribute value pairs should be treated as the only attributes
- of the user or whether they should merely
- be treated as the minimum list."
+ desc "Whether specified attribute value pairs should be treated as the
+ **complete list** (`inclusive`) or the **minimum list** (`minimum`) of
+ attribute/value pairs for the user. Defaults to `minimum`."
newvalues(:inclusive, :minimum)
defaultto :minimum
end
end
end
diff --git a/lib/puppet/type/vlan.rb b/lib/puppet/type/vlan.rb
index e39daf994..01fe6efe8 100644
--- a/lib/puppet/type/vlan.rb
+++ b/lib/puppet/type/vlan.rb
@@ -1,26 +1,26 @@
#
# Manages a Vlan on a given router or switch
#
Puppet::Type.newtype(:vlan) do
- @doc = "This represents a router or switch vlan."
+ @doc = "Manages a VLAN on a router or switch."
apply_to_device
ensurable
newparam(:name) do
- desc "Vlan id. It must be a number"
+ desc "The numeric VLAN ID."
isnamevar
newvalues(/^\d+/)
end
newproperty(:description) do
- desc "Vlan name"
+ desc "The VLAN's name."
end
newparam(:device_url) do
- desc "Url to connect to a router or switch."
+ desc "The URL of the router or switch maintaining this VLAN."
end
end
\ No newline at end of file
diff --git a/lib/puppet/type/whit.rb b/lib/puppet/type/whit.rb
index 4c77915b3..516d5c029 100644
--- a/lib/puppet/type/whit.rb
+++ b/lib/puppet/type/whit.rb
@@ -1,23 +1,27 @@
Puppet::Type.newtype(:whit) do
- desc "The smallest possible resource type, for when you need a resource and naught else."
+ desc "Whits are internal artifacts of Puppet's current implementation, and
+ Puppet suppresses their appearance in all logs. We make no guarantee of
+ the whit's continued existence, and it should never be used in an actual
+ manifest. Use the `anchor` type from the puppetlabs-stdlib module if you
+ need arbitrary whit-like no-op resources."
newparam :name do
desc "The name of the whit, because it must have one."
end
# Hide the fact that we're a whit from logs
def to_s
name.sub(/^completed_|^admissible_/, "")
end
def path
to_s
end
def refresh
# We don't do anything with them, but we need this to
# show that we are "refresh aware" and not break the
- # chain of propogation.
+ # chain of propagation.
end
end
diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb
index 9b4c79428..830b5d748 100644
--- a/lib/puppet/type/yumrepo.rb
+++ b/lib/puppet/type/yumrepo.rb
@@ -1,359 +1,361 @@
# Description of yum repositories
require 'puppet/util/inifile'
module Puppet
# A property for one entry in a .ini-style file
class IniProperty < Puppet::Property
def insync?(is)
# A should property of :absent is the same as nil
if is.nil? && should == :absent
return true
end
super(is)
end
def sync
if safe_insync?(retrieve)
result = nil
else
result = set(self.should)
if should == :absent
resource.section[inikey] = nil
else
resource.section[inikey] = should
end
end
result
end
def retrieve
resource.section[inikey]
end
def inikey
name.to_s
end
# Set the key associated with this property to KEY, instead
# of using the property's NAME
def self.inikey(key)
# Override the inikey instance method
# Is there a way to do this without resorting to strings ?
# Using a block fails because the block can't access
# the variable 'key' in the outer scope
self.class_eval("def inikey ; \"#{key.to_s}\" ; end")
end
end
# Doc string for properties that can be made 'absent'
- ABSENT_DOC="Set this to 'absent' to remove it from the file completely"
+ ABSENT_DOC="Set this to `absent` to remove it from the file completely."
newtype(:yumrepo) do
@doc = "The client-side description of a yum repository. Repository
configurations are found by parsing `/etc/yum.conf` and
- the files indicated by the `reposdir` option in that file
- (see yum.conf(5) for details)
+ the files indicated by the `reposdir` option in that file
+ (see `yum.conf(5)` for details).
Most parameters are identical to the ones documented
- in yum.conf(5)
+ in the `yum.conf(5)` man page.
- Continuation lines that yum supports for example for the
- baseurl are not supported. No attempt is made to access
- files included with the **include** directive"
+ Continuation lines that yum supports (for the `baseurl`, for example)
+ are not supported. This type does not attempt to read or verify the
+ exinstence of files listed in the `include` attribute."
class << self
attr_accessor :filetype
# The writer is only used for testing, there should be no need
# to change yumconf or inifile in any other context
attr_accessor :yumconf
attr_writer :inifile
end
self.filetype = Puppet::Util::FileType.filetype(:flat)
@inifile = nil
@yumconf = "/etc/yum.conf"
# Where to put files for brand new sections
@defaultrepodir = nil
def self.instances
l = []
check = validproperties
clear
inifile.each_section do |s|
next if s.name == "main"
obj = new(:name => s.name, :audit => check)
current_values = obj.retrieve
obj.eachproperty do |property|
if current_values[property].nil?
obj.delete(property.name)
else
property.should = current_values[property]
end
end
obj.delete(:audit)
l << obj
end
l
end
# Return the Puppet::Util::IniConfig::File for the whole yum config
def self.inifile
if @inifile.nil?
@inifile = read
main = @inifile['main']
raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
reposdir = main['reposdir']
reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
reposdir.gsub!(/[\n,]/, " ")
reposdir.split.each do |dir|
Dir::glob("#{dir}/*.repo").each do |file|
@inifile.read(file) if File.file?(file)
end
end
reposdir.split.each do |dir|
if File::directory?(dir) && File::writable?(dir)
@defaultrepodir = dir
break
end
end
end
@inifile
end
# Parse the yum config files. Only exposed for the tests
# Non-test code should use self.inifile to get at the
# underlying file
def self.read
result = Puppet::Util::IniConfig::File.new
result.read(yumconf)
main = result['main']
raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
reposdir = main['reposdir']
reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
reposdir.gsub!(/[\n,]/, " ")
reposdir.split.each do |dir|
Dir::glob("#{dir}/*.repo").each do |file|
result.read(file) if File.file?(file)
end
end
if @defaultrepodir.nil?
reposdir.split.each do |dir|
if File::directory?(dir) && File::writable?(dir)
@defaultrepodir = dir
break
end
end
end
result
end
# Return the Puppet::Util::IniConfig::Section with name NAME
# from the yum config
def self.section(name)
result = inifile[name]
if result.nil?
# Brand new section
path = yumconf
path = File::join(@defaultrepodir, "#{name}.repo") unless @defaultrepodir.nil?
Puppet::info "create new repo #{name} in file #{path}"
result = inifile.add_section(name, path)
end
result
end
# Store all modifications back to disk
def self.store
inifile.store
unless Puppet[:noop]
target_mode = 0644 # FIXME: should be configurable
inifile.each_file do |file|
current_mode = File.stat(file).mode & 0777
unless current_mode == target_mode
Puppet::info "changing mode of #{file} from %03o to %03o" % [current_mode, target_mode]
File.chmod(target_mode, file)
end
end
end
end
# This is only used during testing.
def self.clear
@inifile = nil
@yumconf = "/etc/yum.conf"
@defaultrepodir = nil
end
# Return the Puppet::Util::IniConfig::Section for this yumrepo resource
def section
self.class.section(self[:name])
end
# Store modifications to this yumrepo resource back to disk
def flush
self.class.store
end
newparam(:name) do
desc "The name of the repository. This corresponds to the
- repositoryid parameter in yum.conf(5)."
+ `repositoryid` parameter in `yum.conf(5)`."
isnamevar
end
newproperty(:descr, :parent => Puppet::IniProperty) do
- desc "A human readable description of the repository.
- This corresponds to the name parameter in yum.conf(5).
+ desc "A human-readable description of the repository.
+ This corresponds to the name parameter in `yum.conf(5)`.
#{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(/.*/) { }
inikey "name"
end
newproperty(:mirrorlist, :parent => Puppet::IniProperty) do
desc "The URL that holds the list of mirrors for this repository.
#{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
# Should really check that it's a valid URL
newvalue(/.*/) { }
end
newproperty(:baseurl, :parent => Puppet::IniProperty) do
- desc "The URL for this repository.\n#{ABSENT_DOC}"
+ desc "The URL for this repository. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
# Should really check that it's a valid URL
newvalue(/.*/) { }
end
newproperty(:enabled, :parent => Puppet::IniProperty) do
- desc "Whether this repository is enabled or disabled. Possible
- values are '0', and '1'.\n#{ABSENT_DOC}"
+ desc "Whether this repository is enabled, as represented by a
+ `0` or `1`. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{(0|1)}) { }
end
newproperty(:gpgcheck, :parent => Puppet::IniProperty) do
desc "Whether to check the GPG signature on packages installed
- from this repository. Possible values are '0', and '1'.
- \n#{ABSENT_DOC}"
+ from this repository, as represented by a `0` or `1`.
+ #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{(0|1)}) { }
end
newproperty(:gpgkey, :parent => Puppet::IniProperty) do
desc "The URL for the GPG key with which packages from this
- repository are signed.\n#{ABSENT_DOC}"
+ repository are signed. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
# Should really check that it's a valid URL
newvalue(/.*/) { }
end
newproperty(:include, :parent => Puppet::IniProperty) do
- desc "A URL from which to include the config.\n#{ABSENT_DOC}"
+ desc "The URL of a remote file containing additional yum configuration
+ settings. Puppet does not check for this file's existence or validity.
+ #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
# Should really check that it's a valid URL
newvalue(/.*/) { }
end
newproperty(:exclude, :parent => Puppet::IniProperty) do
desc "List of shell globs. Matching packages will never be
considered in updates or installs for this repo.
#{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(/.*/) { }
end
newproperty(:includepkgs, :parent => Puppet::IniProperty) do
desc "List of shell globs. If this is set, only packages
matching one of the globs will be considered for
- update or install.\n#{ABSENT_DOC}"
+ update or install from this repo. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(/.*/) { }
end
newproperty(:enablegroups, :parent => Puppet::IniProperty) do
- desc "Determines whether yum will allow the use of
- package groups for this repository. Possible
- values are '0', and '1'.\n#{ABSENT_DOC}"
+ desc "Whether yum will allow the use of package groups for this
+ repository, as represented by a `0` or `1`. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{(0|1)}) { }
end
newproperty(:failovermethod, :parent => Puppet::IniProperty) do
- desc "Either 'roundrobin' or 'priority'.\n#{ABSENT_DOC}"
+ desc "The failover methode for this repository; should be either
+ `roundrobin` or `priority`. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{roundrobin|priority}) { }
end
newproperty(:keepalive, :parent => Puppet::IniProperty) do
- desc "Either '1' or '0'. This tells yum whether or not HTTP/1.1
- keepalive should be used with this repository.\n#{ABSENT_DOC}"
+ desc "Whether HTTP/1.1 keepalive should be used with this repository, as
+ represented by a `0` or `1`. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{(0|1)}) { }
end
newproperty(:http_caching, :parent => Puppet::IniProperty) do
- desc "Either 'packages' or 'all' or 'none'.\n#{ABSENT_DOC}"
+ desc "What to cache from this repository. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r(packages|all|none)) { }
end
newproperty(:timeout, :parent => Puppet::IniProperty) do
desc "Number of seconds to wait for a connection before timing
- out.\n#{ABSENT_DOC}"
+ out. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{[0-9]+}) { }
end
newproperty(:metadata_expire, :parent => Puppet::IniProperty) do
desc "Number of seconds after which the metadata will expire.
#{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{[0-9]+}) { }
end
newproperty(:protect, :parent => Puppet::IniProperty) do
desc "Enable or disable protection for this repository. Requires
- that the protectbase plugin is installed and enabled.
+ that the `protectbase` plugin is installed and enabled.
#{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{(0|1)}) { }
end
newproperty(:priority, :parent => Puppet::IniProperty) do
desc "Priority of this repository from 1-99. Requires that
- the priorities plugin is installed and enabled.
+ the `priorities` plugin is installed and enabled.
#{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{[1-9][0-9]?}) { }
end
newproperty(:cost, :parent => Puppet::IniProperty) do
desc "Cost of this repository.\n#{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(%r{\d+}) { }
end
newproperty(:proxy, :parent => Puppet::IniProperty) do
- desc "URL to the proxy server for this repository.\n#{ABSENT_DOC}"
+ desc "URL to the proxy server for this repository. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
# Should really check that it's a valid URL
newvalue(/.*/) { }
end
newproperty(:proxy_username, :parent => Puppet::IniProperty) do
- desc "Username for this proxy.\n#{ABSENT_DOC}"
+ desc "Username for this proxy. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(/.*/) { }
end
newproperty(:proxy_password, :parent => Puppet::IniProperty) do
- desc "Password for this proxy.\n#{ABSENT_DOC}"
+ desc "Password for this proxy. #{ABSENT_DOC}"
newvalue(:absent) { self.should = :absent }
newvalue(/.*/) { }
end
end
end
diff --git a/lib/puppet/type/zfs.rb b/lib/puppet/type/zfs.rb
index 75f821787..08266315f 100644
--- a/lib/puppet/type/zfs.rb
+++ b/lib/puppet/type/zfs.rb
@@ -1,144 +1,146 @@
module Puppet
newtype(:zfs) do
@doc = "Manage zfs. Create destroy and set properties on zfs instances.
-**Autorequires:** If Puppet is managing the zpool at the root of this zfs instance, the zfs resource will autorequire it. If Puppet is managing any parent zfs instances, the zfs resource will autorequire them."
+**Autorequires:** If Puppet is managing the zpool at the root of this zfs
+instance, the zfs resource will autorequire it. If Puppet is managing any
+parent zfs instances, the zfs resource will autorequire them."
ensurable
newparam(:name) do
- desc "The full name for this filesystem. (including the zpool)"
+ desc "The full name for this filesystem (including the zpool)."
end
newproperty(:aclinherit) do
- desc "The aclinherit property. Values: discard | noallow | restricted | passthrough | passthrough-x"
+ desc "The aclinherit property. Valid values are `discard`, `noallow`, `restricted`, `passthrough`, `passthrough-x`."
end
newproperty(:aclmode) do
- desc "The aclmode property. Values: discard | groupmask | passthrough"
+ desc "The aclmode property. Valid values are `discard`, `groupmask`, `passthrough`."
end
newproperty(:atime) do
- desc "The atime property. Values: on | off"
+ desc "The atime property. Valid values are `on`, `off`."
end
newproperty(:canmount) do
- desc "The canmount property. Values: on | off | noauto"
+ desc "The canmount property. Valid values are `on`, `off`, `noauto`."
end
newproperty(:checksum) do
- desc "The checksum property. Values: on | off | fletcher2 | fletcher4 | sha256"
+ desc "The checksum property. Valid values are `on`, `off`, `fletcher2`, `fletcher4`, `sha256`."
end
newproperty(:compression) do
- desc "The compression property. Values: on | off | lzjb | gzip | gzip-[1-9] | zle"
+ desc "The compression property. Valid values are `on`, `off`, `lzjb`, `gzip`, `gzip-[1-9]`, `zle`."
end
newproperty(:copies) do
- desc "The copies property. Values: 1 | 2 | 3"
+ desc "The copies property. Valid values are `1`, `2`, `3`."
end
newproperty(:devices) do
- desc "The devices property. Values: on | off"
+ desc "The devices property. Valid values are `on`, `off`."
end
newproperty(:exec) do
- desc "The exec property. Values: on | off"
+ desc "The exec property. Valid values are `on`, `off`."
end
newproperty(:logbias) do
- desc "The logbias property. Values: latency | throughput"
+ desc "The logbias property. Valid values are `latency`, `throughput`."
end
newproperty(:mountpoint) do
- desc "The mountpoint property. Values: <path> | legacy | none"
+ desc "The mountpoint property. Valid values are `<path>`, `legacy`, `none`."
end
newproperty(:nbmand) do
- desc "The nbmand property. Values: on | off"
+ desc "The nbmand property. Valid values are `on`, `off`."
end
newproperty(:primarycache) do
- desc "The primarycache property. Values: all | none | metadata"
+ desc "The primarycache property. Valid values are `all`, `none`, `metadata`."
end
newproperty(:quota) do
- desc "The quota property. Values: <size> | none"
+ desc "The quota property. Valid values are `<size>`, `none`."
end
newproperty(:readonly) do
- desc "The readonly property. Values: on | off"
+ desc "The readonly property. Valid values are `on`, `off`."
end
newproperty(:recordsize) do
- desc "The recordsize property. Values: 512 to 128k, power of 2"
+ desc "The recordsize property. Valid values are powers of two between 512 and 128k."
end
newproperty(:refquota) do
- desc "The refquota property. Values: <size> | none"
+ desc "The refquota property. Valid values are `<size>`, `none`."
end
newproperty(:refreservation) do
- desc "The refreservation property. Values: <size> | none"
+ desc "The refreservation property. Valid values are `<size>`, `none`."
end
newproperty(:reservation) do
- desc "The reservation property. Values: <size> | none"
+ desc "The reservation property. Valid values are `<size>`, `none`."
end
newproperty(:secondarycache) do
- desc "The secondarycache property. Values: all | none | metadata"
+ desc "The secondarycache property. Valid values are `all`, `none`, `metadata`."
end
newproperty(:setuid) do
- desc "The setuid property. Values: on | off"
+ desc "The setuid property. Valid values are `on`, `off`."
end
newproperty(:shareiscsi) do
- desc "The shareiscsi property. Values: on | off | type=<type>"
+ desc "The shareiscsi property. Valid values are `on`, `off`, `type=<type>`."
end
newproperty(:sharenfs) do
- desc "The sharenfs property. Values: on | off | share(1M) options"
+ desc "The sharenfs property. Valid values are `on`, `off`, share(1M) options"
end
newproperty(:sharesmb) do
- desc "The sharesmb property. Values: on | off | sharemgr(1M) options"
+ desc "The sharesmb property. Valid values are `on`, `off`, sharemgr(1M) options"
end
newproperty(:snapdir) do
- desc "The snapdir property. Values: hidden | visible"
+ desc "The snapdir property. Valid values are `hidden`, `visible`."
end
newproperty(:version) do
- desc "The version property. Values: 1 | 2 | 3 | 4 | current"
+ desc "The version property. Valid values are `1`, `2`, `3`, `4`, `current`."
end
newproperty(:volsize) do
- desc "The volsize property. Values: <size>"
+ desc "The volsize property. Valid values are `<size>`"
end
newproperty(:vscan) do
- desc "The vscan property. Values: on | off"
+ desc "The vscan property. Valid values are `on`, `off`."
end
newproperty(:xattr) do
- desc "The xattr property. Values: on | off"
+ desc "The xattr property. Valid values are `on`, `off`."
end
newproperty(:zoned) do
- desc "The zoned property. Values: on | off"
+ desc "The zoned property. Valid values are `on`, `off`."
end
autorequire(:zpool) do
#strip the zpool off the zfs name and autorequire it
[@parameters[:name].value.split('/')[0]]
end
autorequire(:zfs) do
#slice and dice, we want all the zfs before this one
names = @parameters[:name].value.split('/')
names.slice(1..-2).inject([]) { |a,v| a << "#{a.last}/#{v}" }.collect { |fs| names[0] + fs }
end
end
end
diff --git a/lib/puppet/type/zone.rb b/lib/puppet/type/zone.rb
index 0fc702ccf..0d8e63f17 100644
--- a/lib/puppet/type/zone.rb
+++ b/lib/puppet/type/zone.rb
@@ -1,490 +1,492 @@
Puppet::Type.newtype(:zone) do
- @doc = "Solaris zones.
+ @doc = "Manages Solaris zones.
-**Autorequires:** If Puppet is managing the directory specified as the root of the zone's filesystem (with the `path` attribute), the zone resource will autorequire that directory."
+**Autorequires:** If Puppet is managing the directory specified as the root of
+the zone's filesystem (with the `path` attribute), the zone resource will
+autorequire that directory."
# These properties modify the zone configuration, and they need to provide
# the text separately from syncing it, so all config statements can be rolled
# into a single creation statement.
class ZoneConfigProperty < Puppet::Property
# Perform the config operation.
def sync
provider.setconfig self.configtext
end
end
# Those properties that can have multiple instances.
class ZoneMultiConfigProperty < ZoneConfigProperty
def configtext
list = @should
current_value = self.retrieve
unless current_value.is_a? Symbol
if current_value.is_a? Array
list += current_value
else
list << current_value if current_value
end
end
# Some hackery so we can test whether current_value is an array or a symbol
if current_value.is_a? Array
tmpis = current_value
else
if current_value
tmpis = [current_value]
else
tmpis = []
end
end
rms = []
adds = []
# Collect the modifications to make
list.sort.uniq.collect do |obj|
# Skip objectories that are configured and should be
next if tmpis.include?(obj) and @should.include?(obj)
if tmpis.include?(obj)
rms << obj
else
adds << obj
end
end
# And then perform all of the removals before any of the adds.
(rms.collect { |o| rm(o) } + adds.collect { |o| add(o) }).join("\n")
end
# We want all specified directories to be included.
def insync?(current_value)
if current_value.is_a? Array and @should.is_a? Array
current_value.sort == @should.sort
else
current_value == @should
end
end
end
ensurable do
desc "The running state of the zone. The valid states directly reflect
the states that `zoneadm` provides. The states are linear,
- in that a zone must be `configured` then `installed`, and
+ in that a zone must be `configured`, then `installed`, and
only then can be `running`. Note also that `halt` is currently
used to stop zones."
@states = {}
@parametervalues = []
def self.alias_state(values)
@state_aliases ||= {}
values.each do |nick, name|
@state_aliases[nick] = name
end
end
def self.newvalue(name, hash)
@parametervalues = [] if @parametervalues.is_a? Hash
@parametervalues << name
@states[name] = hash
hash[:name] = name
end
def self.state_name(name)
if other = @state_aliases[name]
other
else
name
end
end
newvalue :absent, :down => :destroy
newvalue :configured, :up => :configure, :down => :uninstall
newvalue :installed, :up => :install, :down => :stop
newvalue :running, :up => :start
alias_state :incomplete => :installed, :ready => :installed, :shutting_down => :running
defaultto :running
def self.state_index(value)
@parametervalues.index(state_name(value))
end
# Return all of the states between two listed values, exclusive
# of the first item.
def self.state_sequence(first, second)
findex = sindex = nil
unless findex = @parametervalues.index(state_name(first))
raise ArgumentError, "'#{first}' is not a valid zone state"
end
unless sindex = @parametervalues.index(state_name(second))
raise ArgumentError, "'#{first}' is not a valid zone state"
end
list = nil
# Apparently ranges are unidirectional, so we have to reverse
# the range op twice.
if findex > sindex
list = @parametervalues[sindex..findex].collect do |name|
@states[name]
end.reverse
else
list = @parametervalues[findex..sindex].collect do |name|
@states[name]
end
end
# The first result is the current state, so don't return it.
list[1..-1]
end
def retrieve
provider.properties[:ensure]
end
def sync
method = nil
if up?
direction = :up
else
direction = :down
end
# We need to get the state we're currently in and just call
# everything between it and us.
self.class.state_sequence(self.retrieve, self.should).each do |state|
if method = state[direction]
warned = false
while provider.processing?
unless warned
info "Waiting for zone to finish processing"
warned = true
end
sleep 1
end
provider.send(method)
else
raise Puppet::DevError, "Cannot move #{direction} from #{st[:name]}"
end
end
("zone_#{self.should}").intern
end
# Are we moving up the property tree?
def up?
current_value = self.retrieve
self.class.state_index(current_value) < self.class.state_index(self.should)
end
end
newparam(:name) do
desc "The name of the zone."
isnamevar
end
newparam(:id) do
desc "The numerical ID of the zone. This number is autogenerated
and cannot be changed."
end
newparam(:clone) do
desc "Instead of installing the zone, clone it from another zone.
If the zone root resides on a zfs file system, a snapshot will be
- used to create the clone, is it redisides on ufs, a copy of the zone
- will be used. The zone you clone from must not be running."
+ used to create the clone; if it resides on a ufs filesystem, a copy of the
+ zone will be used. The zone from which you clone must not be running."
end
newproperty(:ip, :parent => ZoneMultiConfigProperty) do
require 'ipaddr'
desc "The IP address of the zone. IP addresses must be specified
with the interface, separated by a colon, e.g.: bge0:192.168.0.1.
For multiple interfaces, specify them in an array."
# Add an interface.
def add(str)
interface, ip, defrouter = ipsplit(str)
cmd = "add net\n"
cmd += "set physical=#{interface}\n" if interface
cmd += "set address=#{ip}\n" if ip
cmd += "set defrouter=#{defrouter}\n" if defrouter
#if @resource[:iptype] == :shared
cmd += "end\n"
end
# Convert a string into the component interface, address and defrouter
def ipsplit(str)
interface, address, defrouter = str.split(':')
return interface, address, defrouter
end
# Remove an interface.
def rm(str)
interface, ip, defrouter = ipsplit(str)
# Reality seems to disagree with the documentation here; the docs
# specify that braces are required, but they're apparently only
# required if you're specifying multiple values.
if ip
"remove net address=#{ip}"
elsif interface
"remove net interface=#{interface}"
else
raise ArgumentError, "can not remove network based on default router"
end
end
end
newproperty(:iptype, :parent => ZoneConfigProperty) do
- desc "The IP stack type of the zone. Can either be 'shared' or 'exclusive'."
+ desc "The IP stack type of the zone."
defaultto :shared
newvalue :shared
newvalue :exclusive
def configtext
"set ip-type=#{self.should}"
end
end
newproperty(:autoboot, :parent => ZoneConfigProperty) do
desc "Whether the zone should automatically boot."
defaultto true
newvalue(:true) {}
newvalue(:false) {}
def configtext
"set autoboot=#{self.should}"
end
end
newproperty(:pool, :parent => ZoneConfigProperty) do
desc "The resource pool for this zone."
def configtext
"set pool=#{self.should}"
end
end
newproperty(:shares, :parent => ZoneConfigProperty) do
desc "Number of FSS CPU shares allocated to the zone."
def configtext
"add rctl\nset name=zone.cpu-shares\nadd value (priv=privileged,limit=#{self.should},action=none)\nend"
end
end
newproperty(:dataset, :parent => ZoneMultiConfigProperty) do
- desc "The list of datasets delegated to the non global zone from the
- global zone. All datasets must be zfs filesystem names which is
- different than the mountpoint."
+ desc "The list of datasets delegated to the non-global zone from the
+ global zone. All datasets must be zfs filesystem names which are
+ different from the mountpoint."
validate do |value|
unless value !~ /^\//
raise ArgumentError, "Datasets must be the name of a zfs filesystem"
end
end
# Add a zfs filesystem to our list of datasets.
def add(dataset)
"add dataset\nset name=#{dataset}\nend"
end
# Remove a zfs filesystem from our list of datasets.
def rm(dataset)
"remove dataset name=#{dataset}"
end
def should
@should
end
end
newproperty(:inherit, :parent => ZoneMultiConfigProperty) do
desc "The list of directories that the zone inherits from the global
zone. All directories must be fully qualified."
validate do |value|
unless value =~ /^\//
raise ArgumentError, "Inherited filesystems must be fully qualified"
end
end
# Add a directory to our list of inherited directories.
def add(dir)
"add inherit-pkg-dir\nset dir=#{dir}\nend"
end
def rm(dir)
# Reality seems to disagree with the documentation here; the docs
# specify that braces are required, but they're apparently only
# required if you're specifying multiple values.
"remove inherit-pkg-dir dir=#{dir}"
end
def should
@should
end
end
# Specify the sysidcfg file. This is pretty hackish, because it's
# only used to boot the zone the very first time.
newparam(:sysidcfg) do
- desc %{The text to go into the sysidcfg file when the zone is first
+ desc %{The text to go into the `sysidcfg` file when the zone is first
booted. The best way is to use a template:
- # $templatedir/sysidcfg
+ # $confdir/modules/site/templates/sysidcfg.erb
system_locale=en_US
timezone=GMT
terminal=xterms
security_policy=NONE
root_password=<%= password %>
timeserver=localhost
name_service=DNS {domain_name=<%= domain %> name_server=<%= nameserver %>}
network_interface=primary {hostname=<%= realhostname %>
ip_address=<%= ip %>
netmask=<%= netmask %>
protocol_ipv6=no
default_route=<%= defaultroute %>}
nfs4_domain=dynamic
And then call that:
zone { myzone:
- ip => "bge0:192.168.0.23",
- sysidcfg => template(sysidcfg),
- path => "/opt/zones/myzone",
+ ip => "bge0:192.168.0.23",
+ sysidcfg => template("site/sysidcfg.erb"),
+ path => "/opt/zones/myzone",
realhostname => "fully.qualified.domain.name"
}
- The sysidcfg only matters on the first booting of the zone,
+ The `sysidcfg` only matters on the first booting of the zone,
so Puppet only checks for it at that time.}
end
newparam(:path) do
desc "The root of the zone's filesystem. Must be a fully qualified
- file name. If you include '%s' in the path, then it will be
- replaced with the zone's name. At this point, you cannot use
+ file name. If you include `%s` in the path, then it will be
+ replaced with the zone's name. Currently, you cannot use
Puppet to move a zone."
validate do |value|
unless value =~ /^\//
raise ArgumentError, "The zone base must be fully qualified"
end
end
munge do |value|
if value =~ /%s/
value % @resource[:name]
else
value
end
end
end
newparam(:create_args) do
- desc "Arguments to the zonecfg create command. This can be used to create branded zones."
+ desc "Arguments to the `zonecfg` create command. This can be used to create branded zones."
end
newparam(:install_args) do
- desc "Arguments to the zoneadm install command. This can be used to create branded zones."
+ desc "Arguments to the `zoneadm` install command. This can be used to create branded zones."
end
newparam(:realhostname) do
desc "The actual hostname of the zone."
end
# If Puppet is also managing the base dir or its parent dir, list them
# both as prerequisites.
autorequire(:file) do
if @parameters.include? :path
[@parameters[:path].value, ::File.dirname(@parameters[:path].value)]
else
nil
end
end
# If Puppet is also managing the zfs filesystem which is the zone dataset
# then list it as a prerequisite. Zpool's get autorequired by the zfs
# type. We just need to autorequire the dataset zfs itself as the zfs type
# will autorequire all of the zfs parents and zpool.
autorequire(:zfs) do
# Check if we have datasets in our zone configuration
if @parameters.include? :dataset
reqs = []
# Autorequire each dataset
self[:dataset].each { |value|
reqs << value
}
reqs
end
end
def validate_ip(ip, name)
IPAddr.new(ip) if ip
rescue ArgumentError
self.fail "'#{ip}' is an invalid #{name}"
end
validate do
value = self[:ip]
interface, address, defrouter = value.split(':')
if self[:iptype] == :shared
if (interface && address && defrouter.nil?) ||
(interface && address && defrouter)
validate_ip(address, "IP address")
validate_ip(defrouter, "default router")
else
self.fail "ip must contain interface name and ip address separated by a \":\""
end
else
self.fail "only interface may be specified when using exclusive IP stack: #{value}" unless interface && address.nil? && defrouter.nil?
end
self.fail "zone path is required" unless self[:path]
end
def retrieve
provider.flush
if hash = provider.properties and hash[:ensure] != :absent
result = setstatus(hash)
result
else
# Return all properties as absent.
return properties.inject({}) do | prophash, property|
prophash[property] = :absent
prophash
end
end
end
# Take the results of a listing and set everything appropriately.
def setstatus(hash)
prophash = {}
hash.each do |param, value|
next if param == :name
case self.class.attrtype(param)
when :property
# Only try to provide values for the properties we're managing
if prop = self.property(param)
prophash[prop] = value
end
else
self[param] = value
end
end
prophash
end
end
diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb
index 2da713c2b..043deecc4 100755
--- a/lib/puppet/type/zpool.rb
+++ b/lib/puppet/type/zpool.rb
@@ -1,91 +1,91 @@
module Puppet
class Property
class VDev < Property
def flatten_and_sort(array)
array = [array] unless array.is_a? Array
array.collect { |a| a.split(' ') }.flatten.sort
end
def insync?(is)
return @should == [:absent] if is == :absent
flatten_and_sort(is) == flatten_and_sort(@should)
end
end
class MultiVDev < VDev
def insync?(is)
return @should == [:absent] if is == :absent
return false unless is.length == @should.length
is.each_with_index { |list, i| return false unless flatten_and_sort(list) == flatten_and_sort(@should[i]) }
#if we made it this far we are in sync
true
end
end
end
newtype(:zpool) do
@doc = "Manage zpools. Create and delete zpools. The provider WILL NOT SYNC, only report differences.
Supports vdevs with mirrors, raidz, logs and spares."
ensurable
newproperty(:disk, :array_matching => :all, :parent => Puppet::Property::VDev) do
- desc "The disk(s) for this pool. Can be an array or space separated string"
+ desc "The disk(s) for this pool. Can be an array or a space separated string."
end
newproperty(:mirror, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
desc "List of all the devices to mirror for this pool. Each mirror should be a
space separated string:
mirror => [\"disk1 disk2\", \"disk3 disk4\"],
"
validate do |value|
raise ArgumentError, "mirror names must be provided as string separated, not a comma-separated list" if value.include?(",")
end
end
newproperty(:raidz, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
desc "List of all the devices to raid for this pool. Should be an array of
space separated strings:
raidz => [\"disk1 disk2\", \"disk3 disk4\"],
"
validate do |value|
raise ArgumentError, "raid names must be provided as string separated, not a comma-separated list" if value.include?(",")
end
end
newproperty(:spare, :array_matching => :all, :parent => Puppet::Property::VDev) do
desc "Spare disk(s) for this pool."
end
newproperty(:log, :array_matching => :all, :parent => Puppet::Property::VDev) do
- desc "Log disks for this pool. (doesn't support mirroring yet)"
+ desc "Log disks for this pool. This type does not currently support mirroring of log disks."
end
newparam(:pool) do
desc "The name for this pool."
isnamevar
end
newparam(:raid_parity) do
- desc "Determines parity when using raidz property."
+ desc "Determines parity when using the `raidz` parameter."
end
validate do
has_should = [:disk, :mirror, :raidz].select { |prop| self.should(prop) }
self.fail "You cannot specify #{has_should.join(" and ")} on this type (only one)" if has_should.length > 1
end
end
end
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb
index 51fd4d79c..fd34315f2 100644
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -1,507 +1,516 @@
# A module to collect utility functions.
require 'English'
require 'puppet/util/monkey_patches'
require 'sync'
require 'tempfile'
require 'puppet/external/lock'
require 'monitor'
require 'puppet/util/execution_stub'
require 'uri'
module Puppet
# A command failed to execute.
require 'puppet/error'
class ExecutionFailure < Puppet::Error
end
module Util
require 'benchmark'
# These are all for backward compatibility -- these are methods that used
# to be in Puppet::Util but have been moved into external modules.
require 'puppet/util/posix'
extend Puppet::Util::POSIX
@@sync_objects = {}.extend MonitorMixin
def self.activerecord_version
if (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR))
([::ActiveRecord::VERSION::MAJOR, ::ActiveRecord::VERSION::MINOR].join('.').to_f)
else
0
end
end
def self.synchronize_on(x,type)
sync_object,users = 0,1
begin
@@sync_objects.synchronize {
(@@sync_objects[x] ||= [Sync.new,0])[users] += 1
}
@@sync_objects[x][sync_object].synchronize(type) { yield }
ensure
@@sync_objects.synchronize {
@@sync_objects.delete(x) unless (@@sync_objects[x][users] -= 1) > 0
}
end
end
# Change the process to a different user
def self.chuser
if group = Puppet[:group]
begin
Puppet::Util::SUIDManager.change_group(group, true)
rescue => detail
Puppet.warning "could not change to group #{group.inspect}: #{detail}"
$stderr.puts "could not change to group #{group.inspect}"
# Don't exit on failed group changes, since it's
# not fatal
#exit(74)
end
end
if user = Puppet[:user]
begin
Puppet::Util::SUIDManager.change_user(user, true)
rescue => detail
$stderr.puts "Could not change to user #{user}: #{detail}"
exit(74)
end
end
end
# Create instance methods for each of the log levels. This allows
# the messages to be a little richer. Most classes will be calling this
# method.
def self.logmethods(klass, useself = true)
Puppet::Util::Log.eachlevel { |level|
klass.send(:define_method, level, proc { |args|
args = args.join(" ") if args.is_a?(Array)
if useself
Puppet::Util::Log.create(
:level => level,
:source => self,
:message => args
)
else
Puppet::Util::Log.create(
:level => level,
:message => args
)
end
})
}
end
# Proxy a bunch of methods to another object.
def self.classproxy(klass, objmethod, *methods)
classobj = class << klass; self; end
methods.each do |method|
classobj.send(:define_method, method) do |*args|
obj = self.send(objmethod)
obj.send(method, *args)
end
end
end
# Proxy a bunch of methods to another object.
def self.proxy(klass, objmethod, *methods)
methods.each do |method|
klass.send(:define_method, method) do |*args|
obj = self.send(objmethod)
obj.send(method, *args)
end
end
end
# XXX this should all be done using puppet objects, not using
# normal mkdir
def self.recmkdir(dir,mode = 0755)
if FileTest.exist?(dir)
return false
else
tmp = dir.sub(/^\//,'')
path = [File::SEPARATOR]
tmp.split(File::SEPARATOR).each { |dir|
path.push dir
if ! FileTest.exist?(File.join(path))
Dir.mkdir(File.join(path), mode)
elsif FileTest.directory?(File.join(path))
next
else FileTest.exist?(File.join(path))
raise "Cannot create #{dir}: basedir #{File.join(path)} is a file"
end
}
return true
end
end
# Execute a given chunk of code with a new umask.
def self.withumask(mask)
cur = File.umask(mask)
begin
yield
ensure
File.umask(cur)
end
end
def benchmark(*args)
msg = args.pop
level = args.pop
object = nil
if args.empty?
if respond_to?(level)
object = self
else
object = Puppet
end
else
object = args.pop
end
raise Puppet::DevError, "Failed to provide level to :benchmark" unless level
unless level == :none or object.respond_to? level
raise Puppet::DevError, "Benchmarked object does not respond to #{level}"
end
# Only benchmark if our log level is high enough
if level != :none and Puppet::Util::Log.sendlevel?(level)
result = nil
seconds = Benchmark.realtime {
yield
}
object.send(level, msg + (" in %0.2f seconds" % seconds))
return seconds
else
yield
end
end
def which(bin)
if absolute_path?(bin)
return bin if FileTest.file? bin and FileTest.executable? bin
else
ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
dest = File.expand_path(File.join(dir, bin))
if Puppet.features.microsoft_windows? && File.extname(dest).empty?
exts = ENV['PATHEXT']
exts = exts ? exts.split(File::PATH_SEPARATOR) : %w[.COM .EXE .BAT .CMD]
exts.each do |ext|
- bin = File.expand_path(dest + ext)
- return bin if FileTest.file? bin and FileTest.executable? bin
+ destext = File.expand_path(dest + ext)
+ return destext if FileTest.file? destext and FileTest.executable? destext
end
end
return dest if FileTest.file? dest and FileTest.executable? dest
end
end
nil
end
module_function :which
# Determine in a platform-specific way whether a path is absolute. This
# defaults to the local platform if none is specified.
def absolute_path?(path, platform=nil)
# Escape once for the string literal, and once for the regex.
slash = '[\\\\/]'
name = '[^\\\\/]+'
regexes = {
:windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
:posix => %r!^/!,
}
require 'puppet'
platform ||= Puppet.features.microsoft_windows? ? :windows : :posix
!! (path =~ regexes[platform])
end
module_function :absolute_path?
# Convert a path to a file URI
def path_to_uri(path)
return unless path
params = { :scheme => 'file' }
if Puppet.features.microsoft_windows?
path = path.gsub(/\\/, '/')
if unc = /^\/\/([^\/]+)(\/[^\/]+)/.match(path)
params[:host] = unc[1]
path = unc[2]
elsif path =~ /^[a-z]:\//i
path = '/' + path
end
end
params[:path] = URI.escape(path)
begin
URI::Generic.build(params)
rescue => detail
raise Puppet::Error, "Failed to convert '#{path}' to URI: #{detail}"
end
end
module_function :path_to_uri
# Get the path component of a URI
def uri_to_path(uri)
return unless uri.is_a?(URI)
path = URI.unescape(uri.path)
if Puppet.features.microsoft_windows? and uri.scheme == 'file'
if uri.host
path = "//#{uri.host}" + path # UNC
else
path.sub!(/^\//, '')
end
end
path
end
module_function :uri_to_path
# Execute the provided command in a pipe, yielding the pipe object.
def execpipe(command, failonfail = true)
if respond_to? :debug
debug "Executing '#{command}'"
else
Puppet.debug "Executing '#{command}'"
end
command_str = command.respond_to?(:join) ? command.join('') : command
output = open("| #{command_str} 2>&1") do |pipe|
yield pipe
end
if failonfail
unless $CHILD_STATUS == 0
raise ExecutionFailure, output
end
end
output
end
def execfail(command, exception)
output = execute(command)
return output
rescue ExecutionFailure
raise exception, output
end
def execute_posix(command, arguments, stdin, stdout, stderr)
child_pid = Kernel.fork do
- command = Array(command)
+ # We can't just call Array(command), and rely on it returning
+ # things like ['foo'], when passed ['foo'], because
+ # Array(command) will call command.to_a internally, which when
+ # given a string can end up doing Very Bad Things(TM), such as
+ # turning "/tmp/foo;\r\n /bin/echo" into ["/tmp/foo;\r\n", " /bin/echo"]
+ command = [command].flatten
Process.setsid
begin
$stdin.reopen(stdin)
$stdout.reopen(stdout)
$stderr.reopen(stderr)
3.upto(256){|fd| IO::new(fd).close rescue nil}
Puppet::Util::SUIDManager.change_group(arguments[:gid], true) if arguments[:gid]
Puppet::Util::SUIDManager.change_user(arguments[:uid], true) if arguments[:uid]
ENV['LANG'] = ENV['LC_ALL'] = ENV['LC_MESSAGES'] = ENV['LANGUAGE'] = 'C'
Kernel.exec(*command)
rescue => detail
puts detail.to_s
exit!(1)
end
end
child_pid
end
module_function :execute_posix
def execute_windows(command, arguments, stdin, stdout, stderr)
command = command.map do |part|
part.include?(' ') ? %Q["#{part.gsub(/"/, '\"')}"] : part
end.join(" ") if command.is_a?(Array)
process_info = Process.create( :command_line => command, :startup_info => {:stdin => stdin, :stdout => stdout, :stderr => stderr} )
process_info.process_id
end
module_function :execute_windows
# Execute the desired command, and return the status and output.
# def execute(command, failonfail = true, uid = nil, gid = nil)
# :combine sets whether or not to combine stdout/stderr in the output
# :stdinfile sets a file that can be used for stdin. Passing a string
# for stdin is not currently supported.
def execute(command, arguments = {:failonfail => true, :combine => true})
if command.is_a?(Array)
command = command.flatten.map(&:to_s)
str = command.join(" ")
elsif command.is_a?(String)
str = command
end
if respond_to? :debug
debug "Executing '#{str}'"
else
Puppet.debug "Executing '#{str}'"
end
null_file = Puppet.features.microsoft_windows? ? 'NUL' : '/dev/null'
stdin = File.open(arguments[:stdinfile] || null_file, 'r')
stdout = arguments[:squelch] ? File.open(null_file, 'w') : Tempfile.new('puppet')
stderr = arguments[:combine] ? stdout : File.open(null_file, 'w')
-
exec_args = [command, arguments, stdin, stdout, stderr]
if execution_stub = Puppet::Util::ExecutionStub.current_value
return execution_stub.call(*exec_args)
elsif Puppet.features.posix?
child_pid = execute_posix(*exec_args)
- child_status = Process.waitpid2(child_pid).last.exitstatus
+ exit_status = Process.waitpid2(child_pid).last.exitstatus
elsif Puppet.features.microsoft_windows?
child_pid = execute_windows(*exec_args)
- child_status = Process.waitpid2(child_pid).last
+ exit_status = Process.waitpid2(child_pid).last
+ # $CHILD_STATUS is not set when calling win32/process Process.create
+ # and since it's read-only, we can't set it. But we can execute a
+ # a shell that simply returns the desired exit status, which has the
+ # desired effect.
+ %x{#{ENV['COMSPEC']} /c exit #{exit_status}}
end
[stdin, stdout, stderr].each {|io| io.close rescue nil}
# read output in if required
unless arguments[:squelch]
output = wait_for_output(stdout)
Puppet.warning "Could not get output" unless output
end
- if arguments[:failonfail] and child_status != 0
- raise ExecutionFailure, "Execution of '#{str}' returned #{child_status}: #{output}"
+ if arguments[:failonfail] and exit_status != 0
+ raise ExecutionFailure, "Execution of '#{str}' returned #{exit_status}: #{output}"
end
output
end
module_function :execute
def wait_for_output(stdout)
# Make sure the file's actually been written. This is basically a race
# condition, and is probably a horrible way to handle it, but, well, oh
# well.
2.times do |try|
if File.exists?(stdout.path)
output = stdout.open.read
stdout.close(true)
return output
else
time_to_sleep = try / 2.0
Puppet.warning "Waiting for output; will sleep #{time_to_sleep} seconds"
sleep(time_to_sleep)
end
end
nil
end
module_function :wait_for_output
# Create an exclusive lock.
def threadlock(resource, type = Sync::EX)
Puppet::Util.synchronize_on(resource,type) { yield }
end
# Because some modules provide their own version of this method.
alias util_execute execute
module_function :benchmark
def memory
unless defined?(@pmap)
@pmap = which('pmap')
end
if @pmap
%x{#{@pmap} #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i
else
0
end
end
def symbolize(value)
if value.respond_to? :intern
value.intern
else
value
end
end
def symbolizehash(hash)
newhash = {}
hash.each do |name, val|
if name.is_a? String
newhash[name.intern] = val
else
newhash[name] = val
end
end
end
def symbolizehash!(hash)
hash.each do |name, val|
if name.is_a? String
hash[name.intern] = val
hash.delete(name)
end
end
hash
end
module_function :symbolize, :symbolizehash, :symbolizehash!
# Just benchmark, with no logging.
def thinmark
seconds = Benchmark.realtime {
yield
}
seconds
end
module_function :memory, :thinmark
def secure_open(file,must_be_w,&block)
raise Puppet::DevError,"secure_open only works with mode 'w'" unless must_be_w == 'w'
raise Puppet::DevError,"secure_open only requires a block" unless block_given?
Puppet.warning "#{file} was a symlink to #{File.readlink(file)}" if File.symlink?(file)
if File.exists?(file) or File.symlink?(file)
wait = File.symlink?(file) ? 5.0 : 0.1
File.delete(file)
sleep wait # give it a chance to reappear, just in case someone is actively trying something.
end
begin
File.open(file,File::CREAT|File::EXCL|File::TRUNC|File::WRONLY,&block)
rescue Errno::EEXIST
desc = File.symlink?(file) ? "symlink to #{File.readlink(file)}" : File.stat(file).ftype
puts "Warning: #{file} was apparently created by another process (as"
puts "a #{desc}) as soon as it was deleted by this process. Someone may be trying"
puts "to do something objectionable (such as tricking you into overwriting system"
puts "files if you are running as root)."
raise
end
end
module_function :secure_open
end
end
require 'puppet/util/errors'
require 'puppet/util/methodhelper'
require 'puppet/util/metaid'
require 'puppet/util/classgen'
require 'puppet/util/docs'
require 'puppet/util/execution'
require 'puppet/util/logging'
require 'puppet/util/package'
require 'puppet/util/warnings'
diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb
index bd954c665..81bcdf12f 100644
--- a/lib/puppet/util/monkey_patches.rb
+++ b/lib/puppet/util/monkey_patches.rb
@@ -1,113 +1,132 @@
unless defined? JRUBY_VERSION
Process.maxgroups = 1024
end
module RDoc
def self.caller(skip=nil)
in_gem_wrapper = false
Kernel.caller.reject { |call|
in_gem_wrapper ||= call =~ /#{Regexp.escape $0}:\d+:in `load'/
}
end
end
require "yaml"
require "puppet/util/zaml.rb"
class Symbol
def to_zaml(z)
z.emit("!ruby/sym ")
to_s.to_zaml(z)
end
def <=> (other)
self.to_s <=> other.to_s
end
end
[Object, Exception, Integer, Struct, Date, Time, Range, Regexp, Hash, Array, Float, String, FalseClass, TrueClass, Symbol, NilClass, Class].each { |cls|
cls.class_eval do
def to_yaml(ignored=nil)
ZAML.dump(self)
end
end
}
def YAML.dump(*args)
ZAML.dump(*args)
end
#
# Workaround for bug in MRI 1.8.7, see
# http://redmine.ruby-lang.org/issues/show/2708
# for details
#
if RUBY_VERSION == '1.8.7'
class NilClass
def closed?
true
end
end
end
class Object
# ActiveSupport 2.3.x mixes in a dangerous method
# that can cause rspec to fork bomb
# and other strange things like that.
def daemonize
raise NotImplementedError, "Kernel.daemonize is too dangerous, please don't try to use it."
end
# The following code allows callers to make assertions that are only
# checked when the environment variable PUPPET_ENABLE_ASSERTIONS is
# set to a non-empty string. For example:
#
# assert_that { condition }
# assert_that(message) { condition }
if ENV["PUPPET_ENABLE_ASSERTIONS"].to_s != ''
def assert_that(message = nil)
unless yield
raise Exception.new("Assertion failure: #{message}")
end
end
else
def assert_that(message = nil)
end
end
end
# Workaround for yaml_initialize, which isn't supported before Ruby
# 1.8.3.
if RUBY_VERSION == '1.8.1' || RUBY_VERSION == '1.8.2'
YAML.add_ruby_type( /^object/ ) { |tag, val|
type, obj_class = YAML.read_type_class( tag, Object )
r = YAML.object_maker( obj_class, val )
if r.respond_to? :yaml_initialize
r.instance_eval { instance_variables.each { |name| remove_instance_variable name } }
r.yaml_initialize(tag, val)
end
r
}
end
class Array
# Ruby < 1.8.7 doesn't have this method but we use it in tests
def combination(num)
return [] if num < 0 || num > size
return [[]] if num == 0
return map{|e| [e] } if num == 1
tmp = self.dup
self[0, size - (num - 1)].inject([]) do |ret, e|
tmp.shift
ret += tmp.combination(num - 1).map{|a| a.unshift(e) }
end
end unless method_defined? :combination
+
+ alias :count :length unless method_defined? :count
end
class Symbol
def to_proc
Proc.new { |*args| args.shift.__send__(self, *args) }
end unless method_defined? :to_proc
end
+
+
+class String
+ def lines(separator = $/)
+ lines = split(separator)
+ block_given? and lines.each {|line| yield line }
+ lines
+ end
+end
+
+class IO
+ def lines(separator = $/)
+ lines = split(separator)
+ block_given? and lines.each {|line| yield line }
+ lines
+ end
+end
diff --git a/lib/puppet/util/nagios_maker.rb b/lib/puppet/util/nagios_maker.rb
index 863fe24fa..02e5d8bd7 100644
--- a/lib/puppet/util/nagios_maker.rb
+++ b/lib/puppet/util/nagios_maker.rb
@@ -1,60 +1,60 @@
require 'puppet/external/nagios'
require 'puppet/external/nagios/base'
require 'puppet/provider/naginator'
module Puppet::Util::NagiosMaker
# Create a new nagios type, using all of the parameters
# from the parser.
def self.create_nagios_type(name)
name = name.to_sym
full_name = ("nagios_#{name}").to_sym
raise(Puppet::DevError, "No nagios type for #{name}") unless nagtype = Nagios::Base.type(name)
type = Puppet::Type.newtype(full_name) {}
type.ensurable
type.newparam(nagtype.namevar, :namevar => true) do
- desc "The name parameter for Nagios type #{nagtype.name}"
+ desc "The name of this nagios_#{nagtype.name} resource."
end
# We deduplicate the parameters because it makes sense to allow Naginator to have dupes.
nagtype.parameters.uniq.each do |param|
next if param == nagtype.namevar
# We can't turn these parameter names into constants, so at least for now they aren't
# supported.
next if param.to_s =~ /^[0-9]/
type.newproperty(param) do
desc "Nagios configuration file parameter."
end
end
type.newproperty(:target) do
- desc 'target'
+ desc 'The target.'
defaultto do
resource.class.defaultprovider.default_target
end
end
target = "/etc/nagios/#{full_name.to_s}.cfg"
provider = type.provide(:naginator, :parent => Puppet::Provider::Naginator, :default_target => target) {}
provider.nagios_type
type.desc "The Nagios type #{name.to_s}. This resource type is autogenerated using the
model developed in Naginator, and all of the Nagios types are generated using the
same code and the same library.
This type generates Nagios configuration statements in Nagios-parseable configuration
files. By default, the statements will be added to `#{target}`, but
you can send them to a different file by setting their `target` attribute.
You can purge Nagios resources using the `resources` type, but *only*
in the default file locations. This is an architectural limitation.
"
end
end
diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb
index a4921ed2a..ae5f2d44c 100644
--- a/lib/puppet/util/reference.rb
+++ b/lib/puppet/util/reference.rb
@@ -1,140 +1,139 @@
require 'puppet/util/instance_loader'
require 'fileutils'
# Manage Reference Documentation.
class Puppet::Util::Reference
include Puppet::Util
include Puppet::Util::Docs
extend Puppet::Util::InstanceLoader
instance_load(:reference, 'puppet/reference')
def self.footer
"\n\n----------------\n\n*This page autogenerated on #{Time.now}*\n"
end
def self.modes
%w{pdf text}
end
def self.newreference(name, options = {}, &block)
ref = self.new(name, options, &block)
instance_hash(:reference)[symbolize(name)] = ref
ref
end
def self.page(*sections)
depth = 4
# Use the minimum depth
sections.each do |name|
section = reference(name) or raise "Could not find section #{name}"
depth = section.depth if section.depth < depth
end
end
def self.pdf(text)
puts "creating pdf"
Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f|
f.puts text
end
rst2latex = which('rst2latex') || which('rst2latex.py') || raise("Could not find rst2latex")
cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex}
Puppet::Util.secure_open("/tmp/puppetdoc.tex","w") do |f|
# If we get here without an error, /tmp/puppetdoc.tex isn't a tricky cracker's symlink
end
output = %x{#{cmd}}
unless $CHILD_STATUS == 0
$stderr.puts "rst2latex failed"
$stderr.puts output
exit(1)
end
$stderr.puts output
# Now convert to pdf
Dir.chdir("/tmp") do
%x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null}
end
end
def self.references
instance_loader(:reference).loadall
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
def doc
if defined?(@doc)
return "#{@name} - #{@doc}"
else
return @title
end
end
def dynamic?
self.dynamic
end
- def h(name, level)
+ 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|
send(option.to_s + "=", value)
end
meta_def(:generate, &block)
# Now handle the defaults
@title ||= "#{@name.to_s.capitalize} Reference"
@page ||= @title.gsub(/\s+/, '')
@depth ||= 2
@header ||= ""
end
# Indent every line in the chunk except those which begin with '..'.
def indent(text, tab)
text.gsub(/(^|\A)/, tab).gsub(/^ +\.\./, "..")
end
def option(name, value)
":#{name.to_s.capitalize}: #{value}\n"
end
- def paramwrap(name, text, options = {})
- options[:level] ||= 5
- #str = "#{name} : "
- str = h(name, options[:level])
- str += "- **namevar**\n\n" if options[:namevar]
- str += text
- #str += text.gsub(/\n/, "\n ")
-
- str += "\n\n"
- end
-
def text
puts output
end
def to_markdown(withcontents = true)
# First the header
- text = h(@title, 1)
- text += "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n"
+ text = markdown_header(@title, 1)
+ text << "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n"
- text += @header
+ text << @header
- text += generate
+ text << generate
- text += self.class.footer if withcontents
+ text << self.class.footer if withcontents
text
end
end
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index 3039a7b0a..aaa4f44c7 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -1,930 +1,935 @@
require 'puppet'
require 'sync'
require 'getoptlong'
require 'puppet/external/event-loop'
require 'puppet/util/loadedfile'
# The class for handling configuration files.
class Puppet::Util::Settings
include Enumerable
require 'puppet/util/settings/setting'
require 'puppet/util/settings/file_setting'
require 'puppet/util/settings/boolean_setting'
attr_accessor :file
attr_reader :timer
ReadOnly = [:run_mode, :name]
# Retrieve a config value
def [](param)
value(param)
end
# Set a config value. This doesn't set the defaults, it sets the value itself.
def []=(param, value)
set_value(param, value, :memory)
end
# Generate the list of valid arguments, in a format that GetoptLong can
# understand, and add them to the passed option list.
def addargs(options)
# Add all of the config parameters as valid options.
self.each { |name, setting|
setting.getopt_args.each { |args| options << args }
}
options
end
# Generate the list of valid arguments, in a format that OptionParser can
# understand, and add them to the passed option list.
def optparse_addargs(options)
# Add all of the config parameters as valid options.
self.each { |name, setting|
options << setting.optparse_args
}
options
end
# Is our parameter a boolean parameter?
def boolean?(param)
param = param.to_sym
!!(@config.include?(param) and @config[param].kind_of? BooleanSetting)
end
# Remove all set values, potentially skipping cli values.
def clear(exceptcli = false)
@sync.synchronize do
unsafe_clear(exceptcli)
end
end
# Remove all set values, potentially skipping cli values.
def unsafe_clear(exceptcli = false)
@values.each do |name, values|
@values.delete(name) unless exceptcli and name == :cli
end
# Don't clear the 'used' in this case, since it's a config file reparse,
# and we want to retain this info.
@used = [] unless exceptcli
@cache.clear
end
# This is mostly just used for testing.
def clearused
@cache.clear
@used = []
end
# Do variable interpolation on the value.
def convert(value, environment = nil)
return value unless value
return value unless value.is_a? String
newval = value.gsub(/\$(\w+)|\$\{(\w+)\}/) do |value|
varname = $2 || $1
if varname == "environment" and environment
environment
elsif pval = self.value(varname, environment)
pval
else
raise Puppet::DevError, "Could not find value for #{value}"
end
end
newval
end
# Return a value's description.
def description(name)
if obj = @config[name.to_sym]
obj.desc
else
nil
end
end
def each
@config.each { |name, object|
yield name, object
}
end
# Iterate over each section name.
def eachsection
yielded = []
@config.each do |name, object|
section = object.section
unless yielded.include? section
yield section
yielded << section
end
end
end
# Return an object by name.
def setting(param)
param = param.to_sym
@config[param]
end
# Handle a command-line argument.
def handlearg(opt, value = nil)
@cache.clear
value &&= munge_value(value)
str = opt.sub(/^--/,'')
bool = true
newstr = str.sub(/^no-/, '')
if newstr != str
str = newstr
bool = false
end
str = str.intern
if @config[str].is_a?(Puppet::Util::Settings::BooleanSetting)
if value == "" or value.nil?
value = bool
end
end
set_value(str, value, :cli)
end
def include?(name)
name = name.intern if name.is_a? String
@config.include?(name)
end
# check to see if a short name is already defined
def shortinclude?(short)
short = short.intern if name.is_a? String
@shortnames.include?(short)
end
# Create a new collection of config settings.
def initialize
@config = {}
@shortnames = {}
@created = []
@searchpath = nil
# Mutex-like thing to protect @values
@sync = Sync.new
# Keep track of set values.
@values = Hash.new { |hash, key| hash[key] = {} }
# And keep a per-environment cache
@cache = Hash.new { |hash, key| hash[key] = {} }
# The list of sections we've used.
@used = []
end
# NOTE: ACS ahh the util classes. . .sigh
# as part of a fix for 1183, I pulled the logic for the following 5 methods out of the executables and puppet.rb
# They probably deserve their own class, but I don't want to do that until I can refactor environments
# its a little better than where they were
# Prints the contents of a config file with the available config settings, or it
# prints a single value of a config setting.
def print_config_options
env = value(:environment)
val = value(:configprint)
if val == "all"
hash = {}
each do |name, obj|
val = value(name,env)
val = val.inspect if val == ""
hash[name] = val
end
hash.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, val|
puts "#{name} = #{val}"
end
else
val.split(/\s*,\s*/).sort.each do |v|
if include?(v)
#if there is only one value, just print it for back compatibility
if v == val
puts value(val,env)
break
end
puts "#{v} = #{value(v,env)}"
else
puts "invalid parameter: #{v}"
return false
end
end
end
true
end
def generate_config
puts to_config
true
end
def generate_manifest
puts to_manifest
true
end
def print_configs
return print_config_options if value(:configprint) != ""
return generate_config if value(:genconfig)
generate_manifest if value(:genmanifest)
end
def print_configs?
(value(:configprint) != "" || value(:genconfig) || value(:genmanifest)) && true
end
# Return a given object's file metadata.
def metadata(param)
if obj = @config[param.to_sym] and obj.is_a?(FileSetting)
return [:owner, :group, :mode].inject({}) do |meta, p|
if v = obj.send(p)
meta[p] = v
end
meta
end
else
nil
end
end
# Make a directory with the appropriate user, group, and mode
def mkdir(default)
obj = get_config_file_default(default)
Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do
mode = obj.mode || 0750
Dir.mkdir(obj.value, mode)
end
end
# Figure out the section name for the run_mode.
def run_mode
Puppet.run_mode.name
end
# Return all of the parameters associated with a given section.
def params(section = nil)
if section
section = section.intern if section.is_a? String
@config.find_all { |name, obj|
obj.section == section
}.collect { |name, obj|
name
}
else
@config.keys
end
end
# Parse the configuration file. Just provides
# thread safety.
def parse
raise "No :config setting defined; cannot parse unknown config file" unless self[:config]
@sync.synchronize do
unsafe_parse(self[:config])
end
# Create a timer so that this file will get checked automatically
# and reparsed if necessary.
set_filetimeout_timer
end
# Unsafely parse the file -- this isn't thread-safe and causes plenty of problems if used directly.
def unsafe_parse(file)
return unless FileTest.exist?(file)
begin
data = parse_file(file)
rescue => details
puts details.backtrace if Puppet[:trace]
Puppet.err "Could not parse #{file}: #{details}"
return
end
unsafe_clear(true)
metas = {}
data.each do |area, values|
metas[area] = values.delete(:_meta)
values.each do |key,value|
set_value(key, value, area, :dont_trigger_handles => true, :ignore_bad_settings => true )
end
end
# Determine our environment, if we have one.
if @config[:environment]
env = self.value(:environment).to_sym
else
env = "none"
end
# Call any hooks we should be calling.
settings_with_hooks.each do |setting|
each_source(env) do |source|
if value = @values[source][setting.name]
# We still have to use value to retrieve the value, since
# we want the fully interpolated value, not $vardir/lib or whatever.
# This results in extra work, but so few of the settings
# will have associated hooks that it ends up being less work this
# way overall.
setting.handle(self.value(setting.name, env))
break
end
end
end
# We have to do it in the reverse of the search path,
# because multiple sections could set the same value
# and I'm too lazy to only set the metadata once.
searchpath.reverse.each do |source|
source = run_mode if source == :run_mode
source = @name if (@name && source == :name)
if meta = metas[source]
set_metadata(meta)
end
end
end
# Create a new setting. The value is passed in because it's used to determine
# what kind of setting we're creating, but the value itself might be either
# a default or a value, so we can't actually assign it.
def newsetting(hash)
klass = nil
hash[:section] = hash[:section].to_sym if hash[:section]
if type = hash[:type]
unless klass = {:setting => Setting, :file => FileSetting, :boolean => BooleanSetting}[type]
raise ArgumentError, "Invalid setting type '#{type}'"
end
hash.delete(:type)
else
case hash[:default]
when true, false, "true", "false"
klass = BooleanSetting
when /^\$\w+\//, /^\//, /^\w:\//
klass = FileSetting
when String, Integer, Float # nothing
klass = Setting
else
raise ArgumentError, "Invalid value '#{hash[:default].inspect}' for #{hash[:name]}"
end
end
hash[:settings] = self
setting = klass.new(hash)
setting
end
# This has to be private, because it doesn't add the settings to @config
private :newsetting
# Iterate across all of the objects in a given section.
def persection(section)
section = section.to_sym
self.each { |name, obj|
if obj.section == section
yield obj
end
}
end
def file
return @file if @file
if path = self[:config] and FileTest.exist?(path)
@file = Puppet::Util::LoadedFile.new(path)
end
end
# Reparse our config file, if necessary.
def reparse
if file and file.changed?
Puppet.notice "Reparsing #{file.file}"
parse
reuse
end
end
def reuse
return unless defined?(@used)
@sync.synchronize do # yay, thread-safe
new = @used
@used = []
self.use(*new)
end
end
# The order in which to search for values.
def searchpath(environment = nil)
if environment
[:cli, :memory, environment, :run_mode, :main, :mutable_defaults]
else
[:cli, :memory, :run_mode, :main, :mutable_defaults]
end
end
# Get a list of objects per section
def sectionlist
sectionlist = []
self.each { |name, obj|
section = obj.section || "puppet"
sections[section] ||= []
sectionlist << section unless sectionlist.include?(section)
sections[section] << obj
}
return sectionlist, sections
end
def service_user_available?
return @service_user_available if defined?(@service_user_available)
return @service_user_available = false unless user_name = self[:user]
user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure
@service_user_available = user.exists?
end
def legacy_to_mode(type, param)
if not defined?(@app_names)
require 'puppet/util/command_line'
command_line = Puppet::Util::CommandLine.new
@app_names = Puppet::Util::CommandLine::LegacyName.inject({}) do |hash, pair|
app, legacy = pair
command_line.require_application app
hash[legacy.to_sym] = Puppet::Application.find(app).run_mode.name
hash
end
end
if new_type = @app_names[type]
Puppet.warning "You have configuration parameter $#{param} specified in [#{type}], which is a deprecated section. I'm assuming you meant [#{new_type}]"
return new_type
end
type
end
def set_value(param, value, type, options = {})
param = param.to_sym
unless setting = @config[param]
if options[:ignore_bad_settings]
return
else
raise ArgumentError,
"Attempt to assign a value to unknown configuration parameter #{param.inspect}"
end
end
value = setting.munge(value) if setting.respond_to?(:munge)
setting.handle(value) if setting.respond_to?(:handle) and not options[:dont_trigger_handles]
if ReadOnly.include? param and type != :mutable_defaults
raise ArgumentError,
"You're attempting to set configuration parameter $#{param}, which is read-only."
end
type = legacy_to_mode(type, param)
@sync.synchronize do # yay, thread-safe
+ # Allow later inspection to determine if the setting was set on the
+ # command line, or through some other code path. Used for the
+ # `dns_alt_names` option during cert generate. --daniel 2011-10-18
+ setting.setbycli = true if type == :cli
+
@values[type][param] = value
@cache.clear
clearused
# Clear the list of environments, because they cache, at least, the module path.
# We *could* preferentially just clear them if the modulepath is changed,
# but we don't really know if, say, the vardir is changed and the modulepath
# is defined relative to it. We need the defined?(stuff) because of loading
# order issues.
Puppet::Node::Environment.clear if defined?(Puppet::Node) and defined?(Puppet::Node::Environment)
end
value
end
# Set a bunch of defaults in a given section. The sections are actually pretty
# pointless, but they help break things up a bit, anyway.
def setdefaults(section, defs)
section = section.to_sym
call = []
defs.each { |name, hash|
if hash.is_a? Array
unless hash.length == 2
raise ArgumentError, "Defaults specified as an array must contain only the default value and the decription"
end
tmp = hash
hash = {}
[:default, :desc].zip(tmp).each { |p,v| hash[p] = v }
end
name = name.to_sym
hash[:name] = name
hash[:section] = section
raise ArgumentError, "Parameter #{name} is already defined" if @config.include?(name)
tryconfig = newsetting(hash)
if short = tryconfig.short
if other = @shortnames[short]
raise ArgumentError, "Parameter #{other.name} is already using short name '#{short}'"
end
@shortnames[short] = tryconfig
end
@config[name] = tryconfig
# Collect the settings that need to have their hooks called immediately.
# We have to collect them so that we can be sure we're fully initialized before
# the hook is called.
call << tryconfig if tryconfig.call_on_define
}
call.each { |setting| setting.handle(self.value(setting.name)) }
end
# Create a timer to check whether the file should be reparsed.
def set_filetimeout_timer
return unless timeout = self[:filetimeout] and timeout = Integer(timeout) and timeout > 0
timer = EventLoop::Timer.new(:interval => timeout, :tolerance => 1, :start? => true) { self.reparse }
end
# Convert the settings we manage into a catalog full of resources that model those settings.
def to_catalog(*sections)
sections = nil if sections.empty?
catalog = Puppet::Resource::Catalog.new("Settings")
@config.values.find_all { |value| value.is_a?(FileSetting) }.each do |file|
next unless (sections.nil? or sections.include?(file.section))
next unless resource = file.to_resource
next if catalog.resource(resource.ref)
catalog.add_resource(resource)
end
add_user_resources(catalog, sections)
catalog
end
# Convert our list of config settings into a configuration file.
def to_config
str = %{The configuration file for #{Puppet[:name]}. Note that this file
is likely to have unused configuration parameters in it; any parameter that's
valid anywhere in Puppet can be in any config file, even if it's not used.
Every section can specify three special parameters: owner, group, and mode.
These parameters affect the required permissions of any files specified after
their specification. Puppet will sometimes use these parameters to check its
own configured state, so they can be used to make Puppet a bit more self-managing.
Generated on #{Time.now}.
}.gsub(/^/, "# ")
# Add a section heading that matches our name.
if @config.include?(:run_mode)
str += "[#{self[:run_mode]}]\n"
end
eachsection do |section|
persection(section) do |obj|
str += obj.to_config + "\n" unless ReadOnly.include? obj.name or obj.name == :genconfig
end
end
return str
end
# Convert to a parseable manifest
def to_manifest
catalog = to_catalog
catalog.resource_refs.collect do |ref|
catalog.resource(ref).to_manifest
end.join("\n\n")
end
# Create the necessary objects to use a section. This is idempotent;
# you can 'use' a section as many times as you want.
def use(*sections)
sections = sections.collect { |s| s.to_sym }
@sync.synchronize do # yay, thread-safe
sections = sections.reject { |s| @used.include?(s) }
return if sections.empty?
begin
catalog = to_catalog(*sections).to_ral
rescue => detail
puts detail.backtrace if Puppet[:trace]
Puppet.err "Could not create resources for managing Puppet's files and directories in sections #{sections.inspect}: #{detail}"
# We need some way to get rid of any resources created during the catalog creation
# but not cleaned up.
return
end
catalog.host_config = false
catalog.apply do |transaction|
if transaction.any_failed?
report = transaction.report
failures = report.logs.find_all { |log| log.level == :err }
raise "Got #{failures.length} failure(s) while initializing: #{failures.collect { |l| l.to_s }.join("; ")}"
end
end
sections.each { |s| @used << s }
@used.uniq!
end
end
def valid?(param)
param = param.to_sym
@config.has_key?(param)
end
def uninterpolated_value(param, environment = nil)
param = param.to_sym
environment &&= environment.to_sym
# See if we can find it within our searchable list of values
val = catch :foundval do
each_source(environment) do |source|
# Look for the value. We have to test the hash for whether
# it exists, because the value might be false.
@sync.synchronize do
throw :foundval, @values[source][param] if @values[source].include?(param)
end
end
throw :foundval, nil
end
# If we didn't get a value, use the default
val = @config[param].default if val.nil?
val
end
# Find the correct value using our search path. Optionally accept an environment
# in which to search before the other configuration sections.
def value(param, environment = nil)
param = param.to_sym
environment &&= environment.to_sym
# Short circuit to nil for undefined parameters.
return nil unless @config.include?(param)
# Yay, recursion.
#self.reparse unless [:config, :filetimeout].include?(param)
# Check the cache first. It needs to be a per-environment
# cache so that we don't spread values from one env
# to another.
if cached = @cache[environment||"none"][param]
return cached
end
val = uninterpolated_value(param, environment)
if param == :code
# if we interpolate code, all hell breaks loose.
return val
end
# Convert it if necessary
val = convert(val, environment)
# And cache it
@cache[environment||"none"][param] = val
val
end
# Open a file with the appropriate user, group, and mode
def write(default, *args, &bloc)
obj = get_config_file_default(default)
writesub(default, value(obj.name), *args, &bloc)
end
# Open a non-default file under a default dir with the appropriate user,
# group, and mode
def writesub(default, file, *args, &bloc)
obj = get_config_file_default(default)
chown = nil
if Puppet.features.root?
chown = [obj.owner, obj.group]
else
chown = [nil, nil]
end
Puppet::Util::SUIDManager.asuser(*chown) do
mode = obj.mode ? obj.mode.to_i : 0640
args << "w" if args.empty?
args << mode
# Update the umask to make non-executable files
Puppet::Util.withumask(File.umask ^ 0111) do
File.open(file, *args) do |file|
yield file
end
end
end
end
def readwritelock(default, *args, &bloc)
file = value(get_config_file_default(default).name)
tmpfile = file + ".tmp"
sync = Sync.new
raise Puppet::DevError, "Cannot create #{file}; directory #{File.dirname(file)} does not exist" unless FileTest.directory?(File.dirname(tmpfile))
sync.synchronize(Sync::EX) do
File.open(file, ::File::CREAT|::File::RDWR, 0600) do |rf|
rf.lock_exclusive do
if File.exist?(tmpfile)
raise Puppet::Error, ".tmp file already exists for #{file}; Aborting locked write. Check the .tmp file and delete if appropriate"
end
# If there's a failure, remove our tmpfile
begin
writesub(default, tmpfile, *args, &bloc)
rescue
File.unlink(tmpfile) if FileTest.exist?(tmpfile)
raise
end
begin
File.rename(tmpfile, file)
rescue => detail
Puppet.err "Could not rename #{file} to #{tmpfile}: #{detail}"
File.unlink(tmpfile) if FileTest.exist?(tmpfile)
end
end
end
end
end
private
def get_config_file_default(default)
obj = nil
unless obj = @config[default]
raise ArgumentError, "Unknown default #{default}"
end
raise ArgumentError, "Default #{default} is not a file" unless obj.is_a? FileSetting
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?
return unless self[:mkusers]
@config.each do |name, setting|
next unless setting.respond_to?(:owner)
next unless sections.nil? or sections.include?(setting.section)
if user = setting.owner and user != "root" and catalog.resource(:user, user).nil?
resource = Puppet::Resource.new(:user, user, :parameters => {:ensure => :present})
resource[:gid] = self[:group] if self[:group]
catalog.add_resource resource
end
if group = setting.group and ! %w{root wheel}.include?(group) and catalog.resource(:group, group).nil?
catalog.add_resource Puppet::Resource.new(:group, group, :parameters => {:ensure => :present})
end
end
end
# Yield each search source in turn.
def each_source(environment)
searchpath(environment).each do |source|
# Modify the source as necessary.
source = self.run_mode if source == :run_mode
yield source
end
end
# Return all settings that have associated hooks; this is so
# we can call them after parsing the configuration file.
def settings_with_hooks
@config.values.find_all { |setting| setting.respond_to?(:handle) }
end
# Extract extra setting information for files.
def extract_fileinfo(string)
result = {}
value = string.sub(/\{\s*([^}]+)\s*\}/) do
params = $1
params.split(/\s*,\s*/).each do |str|
if str =~ /^\s*(\w+)\s*=\s*([\w\d]+)\s*$/
param, value = $1.intern, $2
result[param] = value
raise ArgumentError, "Invalid file option '#{param}'" unless [:owner, :mode, :group].include?(param)
if param == :mode and value !~ /^\d+$/
raise ArgumentError, "File modes must be numbers"
end
else
raise ArgumentError, "Could not parse '#{string}'"
end
end
''
end
result[:value] = value.sub(/\s*$/, '')
result
end
# Convert arguments into booleans, integers, or whatever.
def munge_value(value)
# Handle different data types correctly
return case value
when /^false$/i; false
when /^true$/i; true
when /^\d+$/i; Integer(value)
when true; true
when false; false
else
value.gsub(/^["']|["']$/,'').sub(/\s+$/, '')
end
end
# This method just turns a file in to a hash of hashes.
def parse_file(file)
text = read_file(file)
result = Hash.new { |names, name|
names[name] = {}
}
count = 0
# Default to 'main' for the section.
section = :main
result[section][:_meta] = {}
text.split(/\n/).each { |line|
count += 1
case line
when /^\s*\[(\w+)\]\s*$/
section = $1.intern # Section names
# Add a meta section
result[section][:_meta] ||= {}
when /^\s*#/; next # Skip comments
when /^\s*$/; next # Skip blanks
when /^\s*(\w+)\s*=\s*(.*?)\s*$/ # settings
var = $1.intern
# We don't want to munge modes, because they're specified in octal, so we'll
# just leave them as a String, since Puppet handles that case correctly.
if var == :mode
value = $2
else
value = munge_value($2)
end
# Check to see if this is a file argument and it has extra options
begin
if value.is_a?(String) and options = extract_fileinfo(value)
value = options[:value]
options.delete(:value)
result[section][:_meta][var] = options
end
result[section][var] = value
rescue Puppet::Error => detail
detail.file = file
detail.line = line
raise
end
else
error = Puppet::Error.new("Could not match line #{line}")
error.file = file
error.line = line
raise error
end
}
result
end
# Read the file in.
def read_file(file)
begin
return File.read(file)
rescue Errno::ENOENT
raise ArgumentError, "No such file #{file}"
rescue Errno::EACCES
raise ArgumentError, "Permission denied to file #{file}"
end
end
# Set file metadata.
def set_metadata(meta)
meta.each do |var, values|
values.each do |param, value|
@config[var].send(param.to_s + "=", value)
end
end
end
end
diff --git a/lib/puppet/util/suidmanager.rb b/lib/puppet/util/suidmanager.rb
index 56f841a38..d733883b4 100644
--- a/lib/puppet/util/suidmanager.rb
+++ b/lib/puppet/util/suidmanager.rb
@@ -1,153 +1,152 @@
require 'puppet/util/warnings'
require 'forwardable'
module Puppet::Util::SUIDManager
include Puppet::Util::Warnings
extend Forwardable
# Note groups= is handled specially due to a bug in OS X 10.6
to_delegate_to_process = [ :euid=, :euid, :egid=, :egid, :uid=, :uid, :gid=, :gid, :groups ]
to_delegate_to_process.each do |method|
def_delegator Process, method
module_function method
end
def osx_maj_ver
return @osx_maj_ver unless @osx_maj_ver.nil?
require 'facter'
# 'kernel' is available without explicitly loading all facts
if Facter.value('kernel') != 'Darwin'
@osx_maj_ver = false
return @osx_maj_ver
end
# But 'macosx_productversion_major' requires it.
Facter.loadfacts
@osx_maj_ver = Facter.value('macosx_productversion_major')
end
module_function :osx_maj_ver
def groups=(grouplist)
if osx_maj_ver == '10.6'
return true
else
return Process.groups = grouplist
end
end
module_function :groups=
def self.root?
return Process.uid == 0 unless Puppet.features.microsoft_windows?
require 'sys/admin'
require 'win32/security'
require 'facter'
majversion = Facter.value(:kernelmajversion)
return false unless majversion
# if Vista or later, check for unrestricted process token
return Win32::Security.elevated_security? unless majversion.to_f < 6.0
group = Sys::Admin.get_group("Administrators", :sid => Win32::Security::SID::BuiltinAdministrators)
group and group.members.index(Sys::Admin.get_login) != nil
end
# Runs block setting uid and gid if provided then restoring original ids
def asuser(new_uid=nil, new_gid=nil)
return yield if Puppet.features.microsoft_windows? or !root?
old_euid, old_egid = self.euid, self.egid
begin
change_group(new_gid) if new_gid
change_user(new_uid) if new_uid
yield
ensure
change_group(old_egid)
change_user(old_euid)
end
end
module_function :asuser
def change_group(group, permanently=false)
gid = convert_xid(:gid, group)
raise Puppet::Error, "No such group #{group}" unless gid
if permanently
begin
Process::GID.change_privilege(gid)
rescue NotImplementedError
Process.egid = gid
Process.gid = gid
end
else
Process.egid = gid
end
end
module_function :change_group
def change_user(user, permanently=false)
uid = convert_xid(:uid, user)
raise Puppet::Error, "No such user #{user}" unless uid
if permanently
begin
Process::UID.change_privilege(uid)
rescue NotImplementedError
# If changing uid, we must be root. So initgroups first here.
initgroups(uid)
Process.euid = uid
Process.uid = uid
end
else
# If we're already root, initgroups before changing euid. If we're not,
# change euid (to root) first.
if Process.euid == 0
initgroups(uid)
Process.euid = uid
else
Process.euid = uid
initgroups(uid)
end
end
end
module_function :change_user
# Make sure the passed argument is a number.
def convert_xid(type, id)
map = {:gid => :group, :uid => :user}
raise ArgumentError, "Invalid id type #{type}" unless map.include?(type)
ret = Puppet::Util.send(type, id)
if ret == nil
raise Puppet::Error, "Invalid #{map[type]}: #{id}"
end
ret
end
module_function :convert_xid
# Initialize supplementary groups
def initgroups(user)
require 'etc'
Process.initgroups(Etc.getpwuid(user).name, Process.gid)
end
module_function :initgroups
def run_and_capture(command, new_uid=nil, new_gid=nil)
output = Puppet::Util.execute(command, :failonfail => false, :combine => true, :uid => new_uid, :gid => new_gid)
[output, $CHILD_STATUS.dup]
end
module_function :run_and_capture
def system(command, new_uid=nil, new_gid=nil)
status = nil
asuser(new_uid, new_gid) do
Kernel.system(command)
status = $CHILD_STATUS.dup
end
status
end
module_function :system
end
-
diff --git a/spec/integration/defaults_spec.rb b/spec/integration/defaults_spec.rb
index d08b5a551..02dbf96d3 100755
--- a/spec/integration/defaults_spec.rb
+++ b/spec/integration/defaults_spec.rb
@@ -1,301 +1,312 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/defaults'
require 'puppet/rails'
describe "Puppet defaults" do
include Puppet::Util::Execution
after { Puppet.settings.clear }
describe "when setting the :factpath" do
it "should add the :factpath to Facter's search paths" do
Facter.expects(:search).with("/my/fact/path")
Puppet.settings[:factpath] = "/my/fact/path"
end
end
describe "when setting the :certname" do
it "should fail if the certname is not downcased" do
lambda { Puppet.settings[:certname] = "Host.Domain.Com" }.should raise_error(ArgumentError)
end
end
describe "when setting :node_name_value" do
it "should default to the value of :certname" do
Puppet.settings[:certname] = 'blargle'
Puppet.settings[:node_name_value].should == 'blargle'
end
end
describe "when setting the :node_name_fact" do
it "should fail when also setting :node_name_value" do
lambda do
Puppet.settings[:node_name_value] = "some value"
Puppet.settings[:node_name_fact] = "some_fact"
end.should raise_error("Cannot specify both the node_name_value and node_name_fact settings")
end
it "should not fail when using the default for :node_name_value" do
lambda do
Puppet.settings[:node_name_fact] = "some_fact"
end.should_not raise_error
end
end
+ describe "when :certdnsnames is set" do
+ it "should not fail" do
+ expect { Puppet[:certdnsnames] = 'fred:wilma' }.should_not raise_error
+ end
+
+ it "should warn the value is ignored" do
+ Puppet.expects(:warning).with {|msg| msg =~ /CVE-2011-3872/ }
+ Puppet[:certdnsnames] = 'fred:wilma'
+ end
+ end
+
describe "when configuring the :crl" do
it "should warn if :cacrl is set to false" do
Puppet.expects(:warning)
Puppet.settings[:cacrl] = 'false'
end
end
describe "when setting the :catalog_format" do
it "should log a deprecation notice" do
Puppet.expects(:warning)
Puppet.settings[:catalog_format] = 'marshal'
end
it "should copy the value to :preferred_serialization_format" do
Puppet.settings[:catalog_format] = 'marshal'
Puppet.settings[:preferred_serialization_format].should == 'marshal'
end
end
it "should have a clientyamldir setting" do
Puppet.settings[:clientyamldir].should_not be_nil
end
it "should have different values for the yamldir and clientyamldir" do
Puppet.settings[:yamldir].should_not == Puppet.settings[:clientyamldir]
end
it "should have a client_datadir setting" do
Puppet.settings[:client_datadir].should_not be_nil
end
it "should have different values for the server_datadir and client_datadir" do
Puppet.settings[:server_datadir].should_not == Puppet.settings[:client_datadir]
end
# See #1232
it "should not specify a user or group for the clientyamldir" do
Puppet.settings.setting(:clientyamldir).owner.should be_nil
Puppet.settings.setting(:clientyamldir).group.should be_nil
end
it "should use the service user and group for the yamldir" do
Puppet.settings.stubs(:service_user_available?).returns true
Puppet.settings.setting(:yamldir).owner.should == Puppet.settings[:user]
Puppet.settings.setting(:yamldir).group.should == Puppet.settings[:group]
end
# See #1232
it "should not specify a user or group for the rundir" do
Puppet.settings.setting(:rundir).owner.should be_nil
Puppet.settings.setting(:rundir).group.should be_nil
end
it "should specify that the host private key should be owned by the service user" do
Puppet.settings.stubs(:service_user_available?).returns true
Puppet.settings.setting(:hostprivkey).owner.should == Puppet.settings[:user]
end
it "should specify that the host certificate should be owned by the service user" do
Puppet.settings.stubs(:service_user_available?).returns true
Puppet.settings.setting(:hostcert).owner.should == Puppet.settings[:user]
end
it "should use a bind address of ''" do
Puppet.settings.clear
Puppet.settings[:bindaddress].should == ""
end
[:factdest].each do |setting|
it "should force the :factdest to be a directory" do
Puppet.settings[setting].should =~ /\/$/
end
end
[:modulepath, :factpath].each do |setting|
it "should configure '#{setting}' not to be a file setting, so multi-directory settings are acceptable" do
Puppet.settings.setting(setting).should be_instance_of(Puppet::Util::Settings::Setting)
end
end
it "should add /usr/sbin and /sbin to the path if they're not there" do
withenv("PATH" => "/usr/bin:/usr/local/bin") do
Puppet.settings[:path] = "none" # this causes it to ignore the setting
ENV["PATH"].split(File::PATH_SEPARATOR).should be_include("/usr/sbin")
ENV["PATH"].split(File::PATH_SEPARATOR).should be_include("/sbin")
end
end
it "should default to pson for the preferred serialization format" do
Puppet.settings.value(:preferred_serialization_format).should == "pson"
end
describe "when enabling storeconfigs" do
before do
Puppet::Resource::Catalog.indirection.stubs(:cache_class=)
Puppet::Node::Facts.indirection.stubs(:cache_class=)
Puppet::Node.indirection.stubs(:cache_class=)
Puppet.features.stubs(:rails?).returns true
end
it "should set the Catalog cache class to :store_configs" do
Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:store_configs)
Puppet.settings[:storeconfigs] = true
end
it "should not set the Catalog cache class to :store_configs if asynchronous storeconfigs is enabled" do
Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:store_configs).never
Puppet.settings.expects(:value).with(:async_storeconfigs).returns true
Puppet.settings[:storeconfigs] = true
end
it "should set the Facts cache class to :store_configs" do
Puppet::Node::Facts.indirection.expects(:cache_class=).with(:store_configs)
Puppet.settings[:storeconfigs] = true
end
it "should set the Node cache class to :store_configs" do
Puppet::Node.indirection.expects(:cache_class=).with(:store_configs)
Puppet.settings[:storeconfigs] = true
end
end
describe "when enabling asynchronous storeconfigs" do
before do
Puppet::Resource::Catalog.indirection.stubs(:cache_class=)
Puppet::Node::Facts.indirection.stubs(:cache_class=)
Puppet::Node.indirection.stubs(:cache_class=)
Puppet.features.stubs(:rails?).returns true
end
it "should set storeconfigs to true" do
Puppet.settings[:async_storeconfigs] = true
Puppet.settings[:storeconfigs].should be_true
end
it "should set the Catalog cache class to :queue" do
Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:queue)
Puppet.settings[:async_storeconfigs] = true
end
it "should set the Facts cache class to :store_configs" do
Puppet::Node::Facts.indirection.expects(:cache_class=).with(:store_configs)
Puppet.settings[:storeconfigs] = true
end
it "should set the Node cache class to :store_configs" do
Puppet::Node.indirection.expects(:cache_class=).with(:store_configs)
Puppet.settings[:storeconfigs] = true
end
end
describe "when enabling thin storeconfigs" do
before do
Puppet::Resource::Catalog.indirection.stubs(:cache_class=)
Puppet::Node::Facts.indirection.stubs(:cache_class=)
Puppet::Node.indirection.stubs(:cache_class=)
Puppet.features.stubs(:rails?).returns true
end
it "should set storeconfigs to true" do
Puppet.settings[:thin_storeconfigs] = true
Puppet.settings[:storeconfigs].should be_true
end
end
it "should have a setting for determining the configuration version and should default to an empty string" do
Puppet.settings[:config_version].should == ""
end
describe "when enabling reports" do
it "should use the default server value when report server is unspecified" do
Puppet.settings[:server] = "server"
Puppet.settings[:report_server].should == "server"
end
it "should use the default masterport value when report port is unspecified" do
Puppet.settings[:masterport] = "1234"
Puppet.settings[:report_port].should == "1234"
end
it "should set report_server when reportserver is set" do
Puppet.settings[:reportserver] = "reportserver"
Puppet.settings[:report_server].should == "reportserver"
end
it "should use report_port when set" do
Puppet.settings[:masterport] = "1234"
Puppet.settings[:report_port] = "5678"
Puppet.settings[:report_port].should == "5678"
end
it "should prefer report_server over reportserver" do
Puppet.settings[:reportserver] = "reportserver"
Puppet.settings[:report_server] = "report_server"
Puppet.settings[:report_server].should == "report_server"
end
end
it "should have a :caname setting that defaults to the cert name" do
Puppet.settings[:certname] = "foo"
Puppet.settings[:ca_name].should == "Puppet CA: foo"
end
it "should have a 'prerun_command' that defaults to the empty string" do
Puppet.settings[:prerun_command].should == ""
end
it "should have a 'postrun_command' that defaults to the empty string" do
Puppet.settings[:postrun_command].should == ""
end
it "should have a 'certificate_revocation' setting that defaults to true" do
Puppet.settings[:certificate_revocation].should be_true
end
it "should have an http_compression setting that defaults to false" do
Puppet.settings[:http_compression].should be_false
end
describe "reportdir" do
subject { Puppet.settings[:reportdir] }
it { should == "#{Puppet[:vardir]}/reports" }
end
describe "reporturl" do
subject { Puppet.settings[:reporturl] }
it { should == "http://localhost:3000/reports/upload" }
end
describe "when configuring color" do
it "should default to ansi", :unless => Puppet.features.microsoft_windows? do
Puppet.settings[:color].should == 'ansi'
end
it "should default to false", :if => Puppet.features.microsoft_windows? do
Puppet.settings[:color].should == 'false'
end
end
describe "daemonize" do
it "should default to true", :unless => Puppet.features.microsoft_windows? do
Puppet.settings[:daemonize].should == true
end
describe "on Windows", :if => Puppet.features.microsoft_windows? do
it "should default to false" do
Puppet.settings[:daemonize].should == false
end
it "should raise an error if set to true" do
lambda { Puppet.settings[:daemonize] = true }.should raise_error(/Cannot daemonize on Windows/)
end
end
end
end
diff --git a/spec/integration/network/client_spec.rb b/spec/integration/network/client_spec.rb
deleted file mode 100755
index 72174c75c..000000000
--- a/spec/integration/network/client_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-require 'puppet/network/client'
-
-describe Puppet::Network::Client do
- %w{ca file report runner status}.each do |name|
- it "should have a #{name} client" do
- Puppet::Network::Client.client(name).should be_instance_of(Class)
- end
-
- [:name, :handler, :drivername].each do |data|
- it "should have a #{data} value for the #{name} client" do
- Puppet::Network::Client.client(name).send(data).should_not be_nil
- end
- end
- end
-end
diff --git a/spec/integration/network/handler_spec.rb b/spec/integration/network/handler_spec.rb
index dc0837c13..e6e607872 100755
--- a/spec/integration/network/handler_spec.rb
+++ b/spec/integration/network/handler_spec.rb
@@ -1,24 +1,24 @@
#!/usr/bin/env rspec
require 'spec_helper'
-require 'puppet/network/client'
+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/type/exec_spec.rb b/spec/integration/type/exec_spec.rb
new file mode 100755
index 000000000..3a29dead7
--- /dev/null
+++ b/spec/integration/type/exec_spec.rb
@@ -0,0 +1,77 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+require 'puppet_spec/files'
+
+describe Puppet::Type.type(:exec) do
+ include PuppetSpec::Files
+
+ let(:catalog) { Puppet::Resource::Catalog.new }
+ let(:path) { tmpfile('exec_provider') }
+ let(:command) { "ruby -e 'File.open(\"#{path}\", \"w\") { |f| f.print \"foo\" }'" }
+
+ before :each do
+ catalog.host_config = false
+ end
+
+ it "should execute the command" do
+ exec = described_class.new :command => command, :path => ENV['PATH']
+
+ catalog.add_resource exec
+ catalog.apply
+
+ File.read(path).should == 'foo'
+ end
+
+ it "should not execute the command if onlyif returns non-zero" do
+ exec = described_class.new(
+ :command => command,
+ :onlyif => "ruby -e 'exit 44'",
+ :path => ENV['PATH']
+ )
+
+ catalog.add_resource exec
+ catalog.apply
+
+ File.should_not be_exist(path)
+ end
+
+ it "should execute the command if onlyif returns zero" do
+ exec = described_class.new(
+ :command => command,
+ :onlyif => "ruby -e 'exit 0'",
+ :path => ENV['PATH']
+ )
+
+ catalog.add_resource exec
+ catalog.apply
+
+ File.read(path).should == 'foo'
+ end
+
+ it "should execute the command if unless returns non-zero" do
+ exec = described_class.new(
+ :command => command,
+ :unless => "ruby -e 'exit 45'",
+ :path => ENV['PATH']
+ )
+
+ catalog.add_resource exec
+ catalog.apply
+
+ File.read(path).should == 'foo'
+ end
+
+ it "should not execute the command if unless returns zero" do
+ exec = described_class.new(
+ :command => command,
+ :unless => "ruby -e 'exit 0'",
+ :path => ENV['PATH']
+ )
+
+ catalog.add_resource exec
+ catalog.apply
+
+ File.should_not be_exist(path)
+ end
+end
diff --git a/spec/integration/util_spec.rb b/spec/integration/util_spec.rb
old mode 100644
new mode 100755
index a50f78326..2b596fd7c
--- a/spec/integration/util_spec.rb
+++ b/spec/integration/util_spec.rb
@@ -1,13 +1,29 @@
#!/usr/bin/env ruby
require 'spec_helper'
describe Puppet::Util do
describe "#execute" do
it "should properly allow stdout and stderr to share a file" do
command = "ruby -e '(1..10).each {|i| (i%2==0) ? $stdout.puts(i) : $stderr.puts(i)}'"
Puppet::Util.execute(command, :combine => true).split.should =~ [*'1'..'10']
end
+
+ it "should return output and set $CHILD_STATUS" do
+ command = "ruby -e 'puts \"foo\"; exit 42'"
+
+ output = Puppet::Util.execute(command, {:failonfail => false})
+
+ output.should == "foo\n"
+ $CHILD_STATUS.exitstatus.should == 42
+ end
+
+ it "should raise an error if non-zero exit status is returned" do
+ command = "ruby -e 'exit 43'"
+
+ expect { Puppet::Util.execute(command) }.to raise_error(Puppet::ExecutionFailure, /Execution of '#{command}' returned 43: /)
+ $CHILD_STATUS.exitstatus.should == 43
+ end
end
end
diff --git a/spec/unit/configurer_spec.rb b/spec/unit/configurer_spec.rb
index 052b167ce..5c660cc31 100755
--- a/spec/unit/configurer_spec.rb
+++ b/spec/unit/configurer_spec.rb
@@ -1,611 +1,611 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/configurer'
describe Puppet::Configurer do
before do
Puppet.settings.stubs(:use).returns(true)
@agent = Puppet::Configurer.new
@agent.stubs(:dostorage)
Puppet::Util::Storage.stubs(:store)
Puppet[:server] = "puppetmaster"
Puppet[:report] = true
end
it "should include the Plugin Handler module" do
Puppet::Configurer.ancestors.should be_include(Puppet::Configurer::PluginHandler)
end
it "should include the Fact Handler module" do
Puppet::Configurer.ancestors.should be_include(Puppet::Configurer::FactHandler)
end
it "should use the puppetdlockfile as its lockfile path" do
Puppet.settings.expects(:value).with(:puppetdlockfile).returns("/my/lock")
Puppet::Configurer.lockfile_path.should == "/my/lock"
end
describe "when executing a pre-run hook" do
it "should do nothing if the hook is set to an empty string" do
Puppet.settings[:prerun_command] = ""
Puppet::Util.expects(:exec).never
@agent.execute_prerun_command
end
it "should execute any pre-run command provided via the 'prerun_command' setting" do
Puppet.settings[:prerun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@agent.execute_prerun_command
end
it "should fail if the command fails" do
Puppet.settings[:prerun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@agent.execute_prerun_command.should be_false
end
end
describe "when executing a post-run hook" do
it "should do nothing if the hook is set to an empty string" do
Puppet.settings[:postrun_command] = ""
Puppet::Util.expects(:exec).never
@agent.execute_postrun_command
end
it "should execute any post-run command provided via the 'postrun_command' setting" do
Puppet.settings[:postrun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@agent.execute_postrun_command
end
it "should fail if the command fails" do
Puppet.settings[:postrun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@agent.execute_postrun_command.should be_false
end
end
describe "when executing a catalog run" do
before do
Puppet.settings.stubs(:use).returns(true)
@agent.stubs(:prepare)
Puppet::Node::Facts.indirection.terminus_class = :memory
@facts = Puppet::Node::Facts.new(Puppet[:node_name_value])
Puppet::Node::Facts.indirection.save(@facts)
@catalog = Puppet::Resource::Catalog.new
@catalog.stubs(:to_ral).returns(@catalog)
Puppet::Resource::Catalog.indirection.terminus_class = :rest
Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog)
@agent.stubs(:send_report)
@agent.stubs(:save_last_run_summary)
Puppet::Util::Log.stubs(:close_all)
end
after :all do
Puppet::Node::Facts.indirection.reset_terminus_class
Puppet::Resource::Catalog.indirection.reset_terminus_class
end
it "should prepare for the run" do
@agent.expects(:prepare)
@agent.run
end
it "should initialize a transaction report if one is not provided" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns report
@agent.run
end
it "should respect node_name_fact when setting the host on a report" do
Puppet[:node_name_fact] = 'my_name_fact'
@facts.values = {'my_name_fact' => 'node_name_from_fact'}
@agent.run.host.should == 'node_name_from_fact'
end
it "should pass the new report to the catalog" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.stubs(:new).returns report
@catalog.expects(:apply).with{|options| options[:report] == report}
@agent.run
end
it "should use the provided report if it was passed one" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).never
@catalog.expects(:apply).with{|options| options[:report] == report}
@agent.run(:report => report)
end
it "should set the report as a log destination" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns report
Puppet::Util::Log.expects(:newdestination).with(report)
Puppet::Util::Log.expects(:close).with(report)
@agent.run
end
it "should retrieve the catalog" do
@agent.expects(:retrieve_catalog)
@agent.run
end
it "should log a failure and do nothing if no catalog can be retrieved" do
@agent.expects(:retrieve_catalog).returns nil
Puppet.expects(:err).with "Could not retrieve catalog; skipping run"
@agent.run
end
it "should apply the catalog with all options to :run" do
@agent.expects(:retrieve_catalog).returns @catalog
@catalog.expects(:apply).with { |args| args[:one] == true }
@agent.run :one => true
end
it "should accept a catalog and use it instead of retrieving a different one" do
@agent.expects(:retrieve_catalog).never
@catalog.expects(:apply)
@agent.run :one => true, :catalog => @catalog
end
it "should benchmark how long it takes to apply the catalog" do
@agent.expects(:benchmark).with(:notice, "Finished catalog run")
@agent.expects(:retrieve_catalog).returns @catalog
@catalog.expects(:apply).never # because we're not yielding
@agent.run
end
it "should execute post-run hooks after the run" do
@agent.expects(:execute_postrun_command)
@agent.run
end
it "should send the report" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
@agent.expects(:send_report).with(report)
@agent.run
end
it "should send the transaction report even if the catalog could not be retrieved" do
@agent.expects(:retrieve_catalog).returns nil
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
@agent.expects(:send_report)
@agent.run
end
it "should send the transaction report even if there is a failure" do
@agent.expects(:retrieve_catalog).raises "whatever"
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
@agent.expects(:send_report)
@agent.run.should be_nil
end
it "should remove the report as a log destination when the run is finished" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
@agent.run
Puppet::Util::Log.destinations.should_not include(report)
end
it "should return the report as the result of the run" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
@agent.run.should equal(report)
end
it "should send the transaction report even if the pre-run command fails" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
Puppet.settings[:prerun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@agent.expects(:send_report)
@agent.run.should be_nil
end
it "should include the pre-run command failure in the report" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
Puppet.settings[:prerun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
- report.expects(:<<).with { |log| log.message =~ /^Could not run command from prerun_command/ }
+ report.expects(:<<).with { |log| log.message.include?("Could not run command from prerun_command") }
@agent.run.should be_nil
end
it "should send the transaction report even if the post-run command fails" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
Puppet.settings[:postrun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@agent.expects(:send_report)
@agent.run.should be_nil
end
it "should include the post-run command failure in the report" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
Puppet.settings[:postrun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
- report.expects(:<<).with { |log| log.message =~ /^Could not run command from postrun_command/ }
+ report.expects(:<<).with { |log| log.message.include?("Could not run command from postrun_command") }
@agent.run.should be_nil
end
it "should execute post-run command even if the pre-run command fails" do
Puppet.settings[:prerun_command] = "/my/precommand"
Puppet.settings[:postrun_command] = "/my/postcommand"
Puppet::Util.expects(:execute).with(["/my/precommand"]).raises(Puppet::ExecutionFailure, "Failed")
Puppet::Util.expects(:execute).with(["/my/postcommand"])
@agent.run.should be_nil
end
it "should finalize the report" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
report.expects(:finalize_report)
@agent.run
end
it "should not apply the catalog if the pre-run command fails" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
Puppet.settings[:prerun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@catalog.expects(:apply).never()
@agent.expects(:send_report)
@agent.run.should be_nil
end
it "should apply the catalog, send the report, and return nil if the post-run command fails" do
report = Puppet::Transaction::Report.new("apply")
Puppet::Transaction::Report.expects(:new).returns(report)
Puppet.settings[:postrun_command] = "/my/command"
Puppet::Util.expects(:execute).with(["/my/command"]).raises(Puppet::ExecutionFailure, "Failed")
@catalog.expects(:apply)
@agent.expects(:send_report)
@agent.run.should be_nil
end
describe "when not using a REST terminus for catalogs" do
it "should not pass any facts when retrieving the catalog" do
Puppet::Resource::Catalog.indirection.terminus_class = :compiler
@agent.expects(:facts_for_uploading).never
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options|
options[:facts].nil?
}.returns @catalog
@agent.run
end
end
describe "when using a REST terminus for catalogs" do
it "should pass the prepared facts and the facts format as arguments when retrieving the catalog" do
Puppet::Resource::Catalog.indirection.terminus_class = :rest
@agent.expects(:facts_for_uploading).returns(:facts => "myfacts", :facts_format => :foo)
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options|
options[:facts] == "myfacts" and options[:facts_format] == :foo
}.returns @catalog
@agent.run
end
end
end
describe "when sending a report" do
include PuppetSpec::Files
before do
Puppet.settings.stubs(:use).returns(true)
@configurer = Puppet::Configurer.new
Puppet[:lastrunfile] = tmpfile('last_run_file')
@report = Puppet::Transaction::Report.new("apply")
end
it "should print a report summary if configured to do so" do
Puppet.settings[:summarize] = true
@report.expects(:summary).returns "stuff"
@configurer.expects(:puts).with("stuff")
@configurer.send_report(@report)
end
it "should not print a report summary if not configured to do so" do
Puppet.settings[:summarize] = false
@configurer.expects(:puts).never
@configurer.send_report(@report)
end
it "should save the report if reporting is enabled" do
Puppet.settings[:report] = true
Puppet::Transaction::Report.indirection.expects(:save).with(@report)
@configurer.send_report(@report)
end
it "should not save the report if reporting is disabled" do
Puppet.settings[:report] = false
Puppet::Transaction::Report.indirection.expects(:save).with(@report).never
@configurer.send_report(@report)
end
it "should save the last run summary if reporting is enabled" do
Puppet.settings[:report] = true
@configurer.expects(:save_last_run_summary).with(@report)
@configurer.send_report(@report)
end
it "should save the last run summary if reporting is disabled" do
Puppet.settings[:report] = false
@configurer.expects(:save_last_run_summary).with(@report)
@configurer.send_report(@report)
end
it "should log but not fail if saving the report fails" do
Puppet.settings[:report] = true
Puppet::Transaction::Report.indirection.expects(:save).raises("whatever")
Puppet.expects(:err)
lambda { @configurer.send_report(@report) }.should_not raise_error
end
end
describe "when saving the summary report file" do
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)
end
it "should write the raw summary to the lastrunfile setting value" do
Puppet::Util::FileLocking.expects(:writelock).with(Puppet[:lastrunfile], 0660)
@configurer.save_last_run_summary(@report)
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)
end
it "should log but not fail if saving the last run summary fails" do
Puppet::Util::FileLocking.expects(:writelock).raises "exception"
Puppet.expects(:err)
lambda { @configurer.save_last_run_summary(@report) }.should_not raise_error
end
end
describe "when retrieving a catalog" do
before do
Puppet.settings.stubs(:use).returns(true)
@agent.stubs(:facts_for_uploading).returns({})
@catalog = Puppet::Resource::Catalog.new
# this is the default when using a Configurer instance
Puppet::Resource::Catalog.indirection.stubs(:terminus_class).returns :rest
@agent.stubs(:convert_catalog).returns @catalog
end
describe "and configured to only retrieve a catalog from the cache" do
before do
Puppet.settings[:use_cached_catalog] = true
end
it "should first look in the cache for a catalog" do
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.never
@agent.retrieve_catalog({}).should == @catalog
end
it "should compile a new catalog if none is found in the cache" do
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
@agent.retrieve_catalog({}).should == @catalog
end
end
it "should use the Catalog class to get its catalog" do
Puppet::Resource::Catalog.indirection.expects(:find).returns @catalog
@agent.retrieve_catalog({})
end
it "should use its node_name_value to retrieve the catalog" do
Facter.stubs(:value).returns "eh"
Puppet.settings[:node_name_value] = "myhost.domain.com"
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| name == "myhost.domain.com" }.returns @catalog
@agent.retrieve_catalog({})
end
it "should default to returning a catalog retrieved directly from the server, skipping the cache" do
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
@agent.retrieve_catalog({}).should == @catalog
end
it "should log and return the cached catalog when no catalog can be retrieved from the server" do
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
Puppet.expects(:notice)
@agent.retrieve_catalog({}).should == @catalog
end
it "should not look in the cache for a catalog if one is returned from the server" do
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.never
@agent.retrieve_catalog({}).should == @catalog
end
it "should return the cached catalog when retrieving the remote catalog throws an exception" do
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.raises "eh"
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog
@agent.retrieve_catalog({}).should == @catalog
end
it "should log and return nil if no catalog can be retrieved from the server and :usecacheonfailure is disabled" do
Puppet.stubs(:[])
Puppet.expects(:[]).with(:usecacheonfailure).returns false
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
Puppet.expects(:warning)
@agent.retrieve_catalog({}).should be_nil
end
it "should return nil if no cached catalog is available and no catalog can be retrieved from the server" do
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil
Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil
@agent.retrieve_catalog({}).should be_nil
end
it "should convert the catalog before returning" do
Puppet::Resource::Catalog.indirection.stubs(:find).returns @catalog
@agent.expects(:convert_catalog).with { |cat, dur| cat == @catalog }.returns "converted catalog"
@agent.retrieve_catalog({}).should == "converted catalog"
end
it "should return nil if there is an error while retrieving the catalog" do
Puppet::Resource::Catalog.indirection.expects(:find).at_least_once.raises "eh"
@agent.retrieve_catalog({}).should be_nil
end
end
describe "when converting the catalog" do
before do
Puppet.settings.stubs(:use).returns(true)
@catalog = Puppet::Resource::Catalog.new
@oldcatalog = stub 'old_catalog', :to_ral => @catalog
end
it "should convert the catalog to a RAL-formed catalog" do
@oldcatalog.expects(:to_ral).returns @catalog
@agent.convert_catalog(@oldcatalog, 10).should equal(@catalog)
end
it "should finalize the catalog" do
@catalog.expects(:finalize)
@agent.convert_catalog(@oldcatalog, 10)
end
it "should record the passed retrieval time with the RAL catalog" do
@catalog.expects(:retrieval_duration=).with 10
@agent.convert_catalog(@oldcatalog, 10)
end
it "should write the RAL catalog's class file" do
@catalog.expects(:write_class_file)
@agent.convert_catalog(@oldcatalog, 10)
end
it "should write the RAL catalog's resource file" do
@catalog.expects(:write_resource_file)
@agent.convert_catalog(@oldcatalog, 10)
end
end
describe "when preparing for a run" do
before do
Puppet.settings.stubs(:use).returns(true)
@agent.stubs(:download_fact_plugins)
@agent.stubs(:download_plugins)
@facts = {"one" => "two", "three" => "four"}
end
it "should initialize the metadata store" do
@agent.class.stubs(:facts).returns(@facts)
@agent.expects(:dostorage)
@agent.prepare({})
end
it "should download fact plugins" do
@agent.expects(:download_fact_plugins)
@agent.prepare({})
end
it "should download plugins" do
@agent.expects(:download_plugins)
@agent.prepare({})
end
end
end
diff --git a/spec/unit/face/ca_spec.rb b/spec/unit/face/ca_spec.rb
index 1df4d7c53..018942e81 100755
--- a/spec/unit/face/ca_spec.rb
+++ b/spec/unit/face/ca_spec.rb
@@ -1,355 +1,389 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/face'
describe Puppet::Face[:ca, '0.1.0'], :unless => Puppet.features.microsoft_windows? do
include PuppetSpec::Files
before :each do
Puppet.run_mode.stubs(:master?).returns(true)
Puppet[:ca] = true
Puppet[:ssldir] = tmpdir("face-ca-ssldir")
Puppet::SSL::Host.ca_location = :only
Puppet[:certificate_revocation] = true
# This is way more intimate than I want to be with the implementation, but
# there doesn't seem any other way to test this. --daniel 2011-07-18
Puppet::SSL::CertificateAuthority.stubs(:instance).returns(
# ...and this actually does the directory creation, etc.
Puppet::SSL::CertificateAuthority.new
)
end
def make_certs(csr_names, crt_names)
Array(csr_names).map do |name|
Puppet::SSL::Host.new(name).generate_certificate_request
end
Array(crt_names).map do |name|
Puppet::SSL::Host.new(name).generate
end
end
context "#verify" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:verify) end
it "should not explode if there is no certificate" do
expect {
subject.verify('random-host').should == {
:host => 'random-host', :valid => false,
:error => 'Could not find a certificate for random-host'
}
}.should_not raise_error
end
it "should not explode if there is only a CSR" do
make_certs('random-host', [])
expect {
subject.verify('random-host').should == {
:host => 'random-host', :valid => false,
:error => 'Could not find a certificate for random-host'
}
}.should_not raise_error
end
it "should verify a signed certificate" do
make_certs([], 'random-host')
subject.verify('random-host').should == {
:host => 'random-host', :valid => true
}
end
it "should not verify a revoked certificate" do
make_certs([], 'random-host')
subject.revoke('random-host')
expect {
subject.verify('random-host').should == {
:host => 'random-host', :valid => false,
:error => 'certificate revoked'
}
}.should_not raise_error
end
it "should verify a revoked certificate if CRL use was turned off" do
make_certs([], 'random-host')
subject.revoke('random-host')
Puppet[:certificate_revocation] = false
subject.verify('random-host').should == {
:host => 'random-host', :valid => true
}
end
end
context "#fingerprint" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:fingerprint) end
it "should have a 'digest' option" do
action.should be_option :digest
end
it "should not explode if there is no certificate" do
expect {
subject.fingerprint('random-host').should be_nil
}.should_not raise_error
end
it "should fingerprint a CSR" do
make_certs('random-host', [])
expect {
subject.fingerprint('random-host').should =~ /^[0-9A-F:]+$/
}.should_not raise_error
end
it "should fingerprint a certificate" do
make_certs([], 'random-host')
subject.fingerprint('random-host').should =~ /^[0-9A-F:]+$/
end
%w{md5 MD5 sha1 ShA1 SHA1 RIPEMD160 sha256 sha512}.each do |digest|
it "should fingerprint with #{digest.inspect}" do
make_certs([], 'random-host')
subject.fingerprint('random-host', :digest => digest).should =~ /^[0-9A-F:]+$/
end
it "should fingerprint with #{digest.to_sym} as a symbol" do
make_certs([], 'random-host')
subject.fingerprint('random-host', :digest => digest.to_sym).
should =~ /^[0-9A-F:]+$/
end
end
end
context "#print" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:print) end
it "should not explode if there is no certificate" do
expect {
subject.print('random-host').should be_nil
}.should_not raise_error
end
it "should return nothing if there is only a CSR" do
make_certs('random-host', [])
expect {
subject.print('random-host').should be_nil
}.should_not raise_error
end
it "should return the certificate content if there is a cert" do
make_certs([], 'random-host')
text = subject.print('random-host')
text.should be_an_instance_of String
text.should =~ /^Certificate:/
text.should =~ /Issuer: CN=Puppet CA: /
text.should =~ /Subject: CN=random-host$/
end
end
context "#sign" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:sign) end
it "should not explode if there is no CSR" do
expect {
subject.sign('random-host').
should == 'Could not find certificate request for random-host'
}.should_not raise_error
end
it "should not explode if there is a signed cert" do
make_certs([], 'random-host')
expect {
subject.sign('random-host').
should == 'Could not find certificate request for random-host'
}.should_not raise_error
end
it "should sign a CSR if one exists" do
make_certs('random-host', [])
subject.sign('random-host').should be_an_instance_of Puppet::SSL::Certificate
list = subject.list(:signed => true)
list.length.should == 1
list.first.name.should == 'random-host'
end
+
+ describe "when the CSR specifies DNS alt names" do
+ let(:host) { Puppet::SSL::Host.new('someone') }
+
+ before :each do
+ host.generate_certificate_request(:dns_alt_names => 'some,alt,names')
+ end
+
+ it "should sign the CSR if DNS alt names are allowed" do
+ subject.sign('someone', :allow_dns_alt_names => true)
+
+ host.certificate.should be_a(Puppet::SSL::Certificate)
+ end
+
+ it "should refuse to sign the CSR if DNS alt names are not allowed" do
+ certname = 'someone'
+ expect do
+ subject.sign(certname)
+ end.to raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError, /CSR '#{certname}' contains subject alternative names \(.*\), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{certname}` to sign this request./i)
+
+ host.certificate.should be_nil
+ end
+ end
end
context "#generate" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:generate) end
it "should generate a certificate if requested" do
subject.list(:all => true).should == []
subject.generate('random-host')
list = subject.list(:signed => true)
list.length.should == 1
list.first.name.should == 'random-host'
end
it "should not explode if a CSR with that name already exists" do
make_certs('random-host', [])
expect {
subject.generate('random-host').should =~ /already has a certificate request/
}.should_not raise_error
end
it "should not explode if the certificate with that name already exists" do
make_certs([], 'random-host')
expect {
subject.generate('random-host').should =~ /already has a certificate/
}.should_not raise_error
end
+
+ it "should include the specified DNS alt names" do
+ subject.generate('some-host', :dns_alt_names => 'some,alt,names')
+
+ host = subject.list(:signed => true).first
+
+ host.name.should == 'some-host'
+ host.certificate.subject_alt_names.should =~ %w[DNS:some DNS:alt DNS:names DNS:some-host]
+
+ subject.list(:pending => true).should be_empty
+ end
end
context "#revoke" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:revoke) end
it "should not explode when asked to revoke something that doesn't exist" do
expect { subject.revoke('nonesuch') }.should_not raise_error
end
it "should let the user know what went wrong" do
subject.revoke('nonesuch').should == 'Nothing was revoked'
end
it "should revoke a certificate" do
make_certs([], 'random-host')
found = subject.list(:all => true, :subject => 'random-host')
subject.get_action(:list).when_rendering(:console).call(found).
should =~ /^\+ random-host/
subject.revoke('random-host')
found = subject.list(:all => true, :subject => 'random-host')
subject.get_action(:list).when_rendering(:console).call(found).
should =~ /^- random-host \([:0-9A-F]+\) \(certificate revoked\)/
end
end
context "#destroy" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:destroy) end
it "should not explode when asked to delete something that doesn't exist" do
expect { subject.destroy('nonesuch') }.should_not raise_error
end
it "should let the user know if nothing was deleted" do
subject.destroy('nonesuch').should == "Nothing was deleted"
end
it "should destroy a CSR, if we have one" do
make_certs('random-host', [])
subject.list(:pending => true, :subject => 'random-host').should_not == []
subject.destroy('random-host')
subject.list(:pending => true, :subject => 'random-host').should == []
end
it "should destroy a certificate, if we have one" do
make_certs([], 'random-host')
subject.list(:signed => true, :subject => 'random-host').should_not == []
subject.destroy('random-host')
subject.list(:signed => true, :subject => 'random-host').should == []
end
it "should tell the user something was deleted" do
make_certs([], 'random-host')
subject.list(:signed => true, :subject => 'random-host').should_not == []
subject.destroy('random-host').
should == "Deleted for random-host: Puppet::SSL::Certificate, Puppet::SSL::Key"
end
end
context "#list" do
let :action do Puppet::Face[:ca, '0.1.0'].get_action(:list) end
context "options" do
subject { Puppet::Face[:ca, '0.1.0'].get_action(:list) }
it { should be_option :pending }
it { should be_option :signed }
it { should be_option :all }
it { should be_option :subject }
end
context "with no hosts in CA" do
[:pending, :signed, :all].each do |type|
it "should return nothing for #{type}" do
subject.list(type => true).should == []
end
it "should not fail when a matcher is passed" do
expect {
subject.list(type => true, :subject => '.').should == []
}.should_not raise_error
end
end
end
context "with some hosts" do
csr_names = (1..3).map {|n| "csr-#{n}" }
crt_names = (1..3).map {|n| "crt-#{n}" }
all_names = csr_names + crt_names
{
{} => csr_names,
{ :pending => true } => csr_names,
{ :signed => true } => crt_names,
{ :all => true } => all_names,
{ :pending => true, :signed => true } => all_names,
}.each do |input, expect|
it "should map #{input.inspect} to #{expect.inspect}" do
make_certs(csr_names, crt_names)
subject.list(input).map(&:name).should =~ expect
end
['', '.', '2', 'none'].each do |pattern|
filtered = expect.select {|x| Regexp.new(pattern).match(x) }
it "should filter all hosts matching #{pattern.inspect} to #{filtered.inspect}" do
make_certs(csr_names, crt_names)
subject.list(input.merge :subject => pattern).map(&:name).should =~ filtered
end
end
end
context "when_rendering :console" do
{ [["csr1.local"], []] => '^ csr1.local ',
[[], ["crt1.local"]] => '^\+ crt1.local ',
[["csr2"], ["crt2"]] => ['^ csr2 ', '^\+ crt2 ']
}.each do |input, pattern|
it "should render #{input.inspect} to match #{pattern.inspect}" do
make_certs(*input)
text = action.when_rendering(:console).call(subject.list(:all => true))
Array(pattern).each do |item|
text.should =~ Regexp.new(item)
end
end
end
end
end
end
actions = %w{destroy list revoke generate sign print verify fingerprint}
actions.each do |action|
it { should be_action action }
it "should fail #{action} when not a CA" do
Puppet[:ca] = false
expect {
case subject.method(action).arity
when -1 then subject.send(action)
when -2 then subject.send(action, 'dummy')
else
raise "#{action} has arity #{subject.method(action).arity}"
end
}.should raise_error(/Not a CA/)
end
end
end
diff --git a/spec/unit/face/certificate_spec.rb b/spec/unit/face/certificate_spec.rb
index 9291d7523..8d0cbcf82 100755
--- a/spec/unit/face/certificate_spec.rb
+++ b/spec/unit/face/certificate_spec.rb
@@ -1,35 +1,206 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/face'
require 'puppet/ssl/host'
describe Puppet::Face[:certificate, '0.0.1'] do
+ include PuppetSpec::Files
+
+ let(:ca) { Puppet::SSL::CertificateAuthority.instance }
+
+ before :each do
+ Puppet[:confdir] = tmpdir('conf')
+ Puppet::SSL::CertificateAuthority.stubs(:ca?).returns true
+
+ Puppet::SSL::Host.ca_location = :local
+
+ # We can't cache the CA between tests, because each one has its own SSL dir.
+ ca = Puppet::SSL::CertificateAuthority.new
+ Puppet::SSL::CertificateAuthority.stubs(:new).returns ca
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns ca
+ end
+
it "should have a ca-location option" do
subject.should be_option :ca_location
end
it "should set the ca location when invoked" do
Puppet::SSL::Host.expects(:ca_location=).with(:local)
- Puppet::SSL::Host.indirection.expects(:save)
+ ca.expects(:sign).with do |name,options|
+ name == "hello, friend"
+ end
+
subject.sign "hello, friend", :ca_location => :local
end
it "(#7059) should set the ca location when an inherited action is invoked" do
Puppet::SSL::Host.expects(:ca_location=).with(:local)
subject.indirection.expects(:find)
subject.find "hello, friend", :ca_location => :local
end
it "should validate the option as required" do
expect do
subject.find 'hello, friend'
end.to raise_exception ArgumentError, /required/i
end
it "should validate the option as a supported value" do
expect do
subject.find 'hello, friend', :ca_location => :foo
end.to raise_exception ArgumentError, /valid values/i
end
+
+ describe "#generate" do
+ let(:options) { {:ca_location => 'local'} }
+ let(:host) { Puppet::SSL::Host.new(hostname) }
+ let(:csr) { host.certificate_request }
+
+ before :each do
+ Puppet[:autosign] = false
+ end
+
+ describe "for the current host" do
+ let(:hostname) { Puppet[:certname] }
+
+ it "should generate a CSR for this host" do
+ subject.generate(hostname, options)
+
+ csr.content.subject.to_s.should == "/CN=#{Puppet[:certname]}"
+ csr.name.should == Puppet[:certname]
+ end
+
+ it "should add dns_alt_names from the global config if not otherwise specified" do
+ Puppet[:dns_alt_names] = 'from,the,config'
+
+ subject.generate(hostname, options)
+
+ expected = %W[DNS:from DNS:the DNS:config DNS:#{hostname}]
+
+ csr.subject_alt_names.should =~ expected
+ end
+
+ it "should add the provided dns_alt_names if they are specified" do
+ Puppet[:dns_alt_names] = 'from,the,config'
+
+ subject.generate(hostname, options.merge(:dns_alt_names => 'explicit,alt,names'))
+
+ expected = %W[DNS:explicit DNS:alt DNS:names DNS:#{hostname}]
+
+ csr.subject_alt_names.should =~ expected
+ end
+ end
+
+ describe "for another host" do
+ let(:hostname) { Puppet[:certname] + 'different' }
+
+ it "should generate a CSR for the specified host" do
+ subject.generate(hostname, options)
+
+ csr.content.subject.to_s.should == "/CN=#{hostname}"
+ csr.name.should == hostname
+ end
+
+ it "should fail if a CSR already exists for the host" do
+ subject.generate(hostname, options)
+
+ expect do
+ subject.generate(hostname, options)
+ end.to raise_error(RuntimeError, /#{hostname} already has a requested certificate; ignoring certificate request/)
+ end
+
+ it "should add not dns_alt_names from the config file" do
+ Puppet[:dns_alt_names] = 'from,the,config'
+
+ subject.generate(hostname, options)
+
+ csr.subject_alt_names.should be_empty
+ end
+
+ it "should add the provided dns_alt_names if they are specified" do
+ Puppet[:dns_alt_names] = 'from,the,config'
+
+ subject.generate(hostname, options.merge(:dns_alt_names => 'explicit,alt,names'))
+
+ expected = %W[DNS:explicit DNS:alt DNS:names DNS:#{hostname}]
+
+ csr.subject_alt_names.should =~ expected
+ end
+ end
+ end
+
+ describe "#sign" do
+ let(:options) { {:ca_location => 'local'} }
+ let(:host) { Puppet::SSL::Host.new(hostname) }
+ let(:hostname) { "foobar" }
+
+ it "should sign the certificate request if one is waiting", :unless => Puppet.features.microsoft_windows? do
+ subject.generate(hostname, options)
+
+ subject.sign(hostname, options)
+
+ host.certificate_request.should be_nil
+ host.certificate.should be_a(Puppet::SSL::Certificate)
+ host.state.should == 'signed'
+ end
+
+ it "should fail if there is no waiting certificate request" do
+ expect do
+ subject.sign(hostname, options)
+ end.to raise_error(ArgumentError, /Could not find certificate request for #{hostname}/)
+ end
+
+ describe "when ca_location is local", :unless => Puppet.features.microsoft_windows? do
+ describe "when the request has dns alt names" do
+ before :each do
+ subject.generate(hostname, options.merge(:dns_alt_names => 'some,alt,names'))
+ end
+
+ it "should refuse to sign the request if allow_dns_alt_names is not set" do
+ expect do
+ subject.sign(hostname, options)
+ end.to raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError,
+ /CSR '#{hostname}' contains subject alternative names \(.*?\), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{hostname}` to sign this request./i)
+
+ host.state.should == 'requested'
+ end
+
+ it "should sign the request if allow_dns_alt_names is set" do
+ expect do
+ subject.sign(hostname, options.merge(:allow_dns_alt_names => true))
+ end.not_to raise_error
+
+ host.state.should == 'signed'
+ end
+ end
+
+ describe "when the request has no dns alt names" do
+ before :each do
+ subject.generate(hostname, options)
+ end
+
+ it "should sign the request if allow_dns_alt_names is set" do
+ expect { subject.sign(hostname, options.merge(:allow_dns_alt_names => true)) }.not_to raise_error
+
+ host.state.should == 'signed'
+ end
+
+ it "should sign the request if allow_dns_alt_names is not set" do
+ expect { subject.sign(hostname, options) }.not_to raise_error
+
+ host.state.should == 'signed'
+ end
+ end
+ end
+
+ describe "when ca_location is remote" do
+ let(:options) { {:ca_location => :remote} }
+ it "should fail if allow-dns-alt-names is specified" do
+ expect do
+ subject.sign(hostname, options.merge(:allow_dns_alt_names => true))
+ end
+ end
+ end
+ end
end
diff --git a/spec/unit/indirector/certificate_request/ca_spec.rb b/spec/unit/indirector/certificate_request/ca_spec.rb
index 9c74f09d1..e5443a26d 100755
--- a/spec/unit/indirector/certificate_request/ca_spec.rb
+++ b/spec/unit/indirector/certificate_request/ca_spec.rb
@@ -1,60 +1,57 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/ssl/host'
-require 'puppet/sslcertificates'
-require 'puppet/sslcertificates/ca'
require 'puppet/indirector/certificate_request/ca'
describe Puppet::SSL::CertificateRequest::Ca, :unless => Puppet.features.microsoft_windows? do
include PuppetSpec::Files
before :each do
Puppet[:ssldir] = tmpdir('ssl')
Puppet::SSL::Host.ca_location = :local
Puppet[:localcacert] = Puppet[:cacert]
- Puppet::SSLCertificates::CA.new.mkrootcert
@ca = Puppet::SSL::CertificateAuthority.new
end
after :all do
Puppet::SSL::Host.ca_location = :none
end
it "should have documentation" do
Puppet::SSL::CertificateRequest::Ca.doc.should be_instance_of(String)
end
it "should use the :csrdir as the collection directory" do
Puppet.settings.expects(:value).with(:csrdir).returns "/request/dir"
Puppet::SSL::CertificateRequest::Ca.collection_directory.should == "/request/dir"
end
it "should overwrite the previous certificate request if allow_duplicate_certs is true" do
Puppet[:allow_duplicate_certs] = true
host = Puppet::SSL::Host.new("foo")
host.generate_certificate_request
@ca.sign(host.name)
Puppet::SSL::Host.indirection.find("foo").generate_certificate_request
Puppet::SSL::Certificate.indirection.find("foo").name.should == "foo"
Puppet::SSL::CertificateRequest.indirection.find("foo").name.should == "foo"
Puppet::SSL::Host.indirection.find("foo").state.should == "requested"
end
it "should reject a new certificate request if allow_duplicate_certs is false" do
Puppet[:allow_duplicate_certs] = false
host = Puppet::SSL::Host.new("bar")
host.generate_certificate_request
@ca.sign(host.name)
expect { Puppet::SSL::Host.indirection.find("bar").generate_certificate_request }.should raise_error(/ignoring certificate request/)
Puppet::SSL::Certificate.indirection.find("bar").name.should == "bar"
Puppet::SSL::CertificateRequest.indirection.find("bar").should be_nil
Puppet::SSL::Host.indirection.find("bar").state.should == "signed"
end
end
diff --git a/spec/unit/indirector/node/store_configs_spec.rb b/spec/unit/indirector/node/store_configs_spec.rb
index 004ea4ed1..6d5f88631 100755
--- a/spec/unit/indirector/node/store_configs_spec.rb
+++ b/spec/unit/indirector/node/store_configs_spec.rb
@@ -1,16 +1,17 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/node'
+require 'puppet/indirector/memory'
require 'puppet/indirector/node/store_configs'
class Puppet::Node::StoreConfigsTesting < Puppet::Indirector::Memory
end
describe Puppet::Node::StoreConfigs do
after :each do
Puppet::Node.indirection.reset_terminus_class
Puppet::Node.indirection.cache_class = nil
end
it_should_behave_like "a StoreConfigs terminus"
end
diff --git a/spec/unit/indirector/rest_spec.rb b/spec/unit/indirector/rest_spec.rb
index 042b7ca16..f18e99a3c 100755
--- a/spec/unit/indirector/rest_spec.rb
+++ b/spec/unit/indirector/rest_spec.rb
@@ -1,568 +1,567 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/indirector/rest'
shared_examples_for "a REST http call" do
it "should accept a path" do
lambda { @search.send(@method, *@arguments) }.should_not raise_error(ArgumentError)
end
it "should require a path" do
lambda { @searcher.send(@method) }.should raise_error(ArgumentError)
end
it "should return the results of deserializing the response to the request" do
conn = mock 'connection'
conn.stubs(:put).returns @response
conn.stubs(:delete).returns @response
conn.stubs(:get).returns @response
Puppet::Network::HttpPool.stubs(:http_instance).returns conn
@searcher.expects(:deserialize).with(@response).returns "myobject"
@searcher.send(@method, *@arguments).should == 'myobject'
end
end
describe Puppet::Indirector::REST do
before :all do
Puppet::Indirector::Terminus.stubs(:register_terminus_class)
@model = stub('model', :supported_formats => %w{}, :convert_from => nil)
@instance = stub('model instance', :name= => nil)
@indirection = stub('indirection', :name => :mystuff, :register_terminus_type => nil, :model => @model)
Puppet::Indirector::Indirection.expects(:instance).returns(@indirection)
module This
module Is
module A
module Test
end
end
end
end
@rest_class = class This::Is::A::Test::Class < Puppet::Indirector::REST
self
end
end
before :each do
@response = stub('mock response', :body => 'result', :code => "200")
@response.stubs(:[]).with('content-type').returns "text/plain"
@response.stubs(:[]).with('content-encoding').returns nil
@searcher = @rest_class.new
@searcher.stubs(:model).returns @model
end
it "should include the v1 REST API module" do
Puppet::Indirector::REST.ancestors.should be_include(Puppet::Network::HTTP::API::V1)
end
it "should have a method for specifying what setting a subclass should use to retrieve its server" do
@rest_class.should respond_to(:use_server_setting)
end
it "should use any specified setting to pick the server" do
@rest_class.expects(:server_setting).returns :servset
Puppet.settings.expects(:value).with(:servset).returns "myserver"
@rest_class.server.should == "myserver"
end
it "should default to :server for the server setting" do
@rest_class.expects(:server_setting).returns nil
Puppet.settings.expects(:value).with(:server).returns "myserver"
@rest_class.server.should == "myserver"
end
it "should have a method for specifying what setting a subclass should use to retrieve its port" do
@rest_class.should respond_to(:use_port_setting)
end
it "should use any specified setting to pick the port" do
@rest_class.expects(:port_setting).returns :servset
Puppet.settings.expects(:value).with(:servset).returns "321"
@rest_class.port.should == 321
end
it "should default to :port for the port setting" do
@rest_class.expects(:port_setting).returns nil
Puppet.settings.expects(:value).with(:masterport).returns "543"
@rest_class.port.should == 543
end
describe "when making http requests" do
+ include PuppetSpec::Files
+
it "should provide a suggestive error message when certificate verify failed" do
connection = Net::HTTP.new('my_server', 8140)
@searcher.stubs(:network).returns(connection)
connection.stubs(:get).raises(OpenSSL::SSL::SSLError.new('certificate verify failed'))
expect do
@searcher.http_request(:get, stub('request'))
end.to raise_error(/This is often because the time is out of sync on the server or client/)
end
- it "should provide a helpful error message when hostname was not match with server certificate" do
- Puppet[:certdnsnames] = 'foo:bar:baz'
- csr = OpenSSL::X509::Request.new
- csr.subject = OpenSSL::X509::Name.new([['CN', 'not_my_server']])
- csr.public_key = OpenSSL::PKey::RSA.generate(Puppet[:keylength]).public_key
- cert = Puppet::SSL::CertificateFactory.new('server', csr, csr, 14).result
+ it "should provide a helpful error message when hostname was not match with server certificate", :unless => Puppet.features.microsoft_windows? do
+ Puppet[:confdir] = tmpdir('conf')
+ cert = Puppet::SSL::CertificateAuthority.new.generate('not_my_server', :dns_alt_names => 'foo,bar,baz').content
connection = Net::HTTP.new('my_server', 8140)
@searcher.stubs(:network).returns(connection)
ssl_context = OpenSSL::SSL::SSLContext.new
ssl_context.stubs(:current_cert).returns(cert)
connection.stubs(:get).with do
connection.verify_callback.call(true, ssl_context)
end.raises(OpenSSL::SSL::SSLError.new('hostname was not match with server certificate'))
msg = /Server hostname 'my_server' did not match server certificate; expected one of (.+)/
expect { @searcher.http_request(:get, stub('request')) }.to(
raise_error(Puppet::Error, msg) do |error|
error.message =~ msg
- $1.split(', ').should =~ ['foo', 'bar', 'baz', 'not_my_server']
+ $1.split(', ').should =~ %w[DNS:foo DNS:bar DNS:baz DNS:not_my_server not_my_server]
end
)
end
it "should pass along the error message otherwise" do
connection = Net::HTTP.new('my_server', 8140)
@searcher.stubs(:network).returns(connection)
connection.stubs(:get).raises(OpenSSL::SSL::SSLError.new('some other message'))
expect do
@searcher.http_request(:get, stub('request'))
end.to raise_error(/some other message/)
end
end
describe "when deserializing responses" do
it "should return nil if the response code is 404" do
response = mock 'response'
response.expects(:code).returns "404"
@searcher.deserialize(response).should be_nil
end
[300,400,403,405,500,501,502,503,504].each { |rc|
describe "when the response code is #{rc}" do
before :each do
@model.expects(:convert_from).never
@response = mock 'response'
@response.stubs(:code).returns rc.to_s
@response.stubs(:[]).with('content-encoding').returns nil
@response.stubs(:message).returns "There was a problem (header)"
end
it "should fail" do
@response.stubs(:body).returns nil
lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError)
end
it "should take the error message from the body, if present" do
@response.stubs(:body).returns "There was a problem (body)"
lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (body)")
end
it "should take the error message from the response header if the body is empty" do
@response.stubs(:body).returns ""
lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)")
end
it "should take the error message from the response header if the body is absent" do
@response.stubs(:body).returns nil
lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)")
end
describe "and with http compression" do
it "should uncompress the body" do
@response.stubs(:body).returns("compressed body")
@searcher.expects(:uncompress_body).with(@response).returns("uncompressed")
lambda { @searcher.deserialize(@response) }.should raise_error { |e| e.message =~ /uncompressed/ }
end
end
end
}
it "should return the results of converting from the format specified by the content-type header if the response code is in the 200s" do
@model.expects(:convert_from).with("myformat", "mydata").returns "myobject"
response = mock 'response'
response.stubs(:[]).with("content-type").returns "myformat"
response.stubs(:[]).with("content-encoding").returns nil
response.stubs(:body).returns "mydata"
response.stubs(:code).returns "200"
@searcher.deserialize(response).should == "myobject"
end
it "should convert and return multiple instances if the return code is in the 200s and 'multiple' is specified" do
@model.expects(:convert_from_multiple).with("myformat", "mydata").returns "myobjects"
response = mock 'response'
response.stubs(:[]).with("content-type").returns "myformat"
response.stubs(:[]).with("content-encoding").returns nil
response.stubs(:body).returns "mydata"
response.stubs(:code).returns "200"
@searcher.deserialize(response, true).should == "myobjects"
end
it "should strip the content-type header to keep only the mime-type" do
@model.expects(:convert_from).with("text/plain", "mydata").returns "myobject"
response = mock 'response'
response.stubs(:[]).with("content-type").returns "text/plain; charset=utf-8"
response.stubs(:[]).with("content-encoding").returns nil
response.stubs(:body).returns "mydata"
response.stubs(:code).returns "200"
@searcher.deserialize(response)
end
it "should uncompress the body" do
@model.expects(:convert_from).with("myformat", "uncompressed mydata").returns "myobject"
response = mock 'response'
response.stubs(:[]).with("content-type").returns "myformat"
response.stubs(:body).returns "compressed mydata"
response.stubs(:code).returns "200"
@searcher.expects(:uncompress_body).with(response).returns("uncompressed mydata")
@searcher.deserialize(response).should == "myobject"
end
end
describe "when creating an HTTP client" do
before do
Puppet.settings.stubs(:value).returns("rest_testing")
end
it "should use the class's server and port if the indirection request provides neither" do
@request = stub 'request', :key => "foo", :server => nil, :port => nil
@searcher.class.expects(:port).returns 321
@searcher.class.expects(:server).returns "myserver"
Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn"
@searcher.network(@request).should == "myconn"
end
it "should use the server from the indirection request if one is present" do
@request = stub 'request', :key => "foo", :server => "myserver", :port => nil
@searcher.class.stubs(:port).returns 321
Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn"
@searcher.network(@request).should == "myconn"
end
it "should use the port from the indirection request if one is present" do
@request = stub 'request', :key => "foo", :server => nil, :port => 321
@searcher.class.stubs(:server).returns "myserver"
Puppet::Network::HttpPool.expects(:http_instance).with("myserver", 321).returns "myconn"
@searcher.network(@request).should == "myconn"
end
end
describe "when doing a find" do
before :each do
@connection = stub('mock http connection', :get => @response, :verify_callback= => nil)
@searcher.stubs(:network).returns(@connection) # neuter the network connection
# Use a key with spaces, so we can test escaping
@request = Puppet::Indirector::Request.new(:foo, :find, "foo bar", :environment => "myenv")
end
describe "with a large body" do
it "should use the POST http method" do
params = {}
'aa'.upto('zz') do |s|
params[s] = 'foo'
end
# The request special-cases this parameter, and it
# won't be passed on to the server, so we remove it here
# to avoid a failure.
params.delete('ip')
@request = Puppet::Indirector::Request.new(:foo, :find, "foo bar", params.merge(:environment => "myenv"))
@connection.expects(:post).with do |uri, body|
uri == "/myenv/foo/foo%20bar" and body.split("&").sort == params.map {|key,value| "#{key}=#{value}"}.sort
end.returns(@response)
@searcher.find(@request)
end
end
describe "with a small body" do
it "should use the GET http method" do
@searcher.expects(:network).returns @connection
@connection.expects(:get).returns @response
@searcher.find(@request)
end
end
it "should deserialize and return the http response, setting name" do
@connection.expects(:get).returns @response
instance = stub 'object'
instance.expects(:name=)
@searcher.expects(:deserialize).with(@response).returns instance
@searcher.find(@request).should == instance
end
it "should deserialize and return the http response, and not require name=" do
@connection.expects(:get).returns @response
instance = stub 'object'
@searcher.expects(:deserialize).with(@response).returns instance
@searcher.find(@request).should == instance
end
it "should use the URI generated by the Handler module" do
@connection.expects(:get).with { |path, args| path == "/myenv/foo/foo%20bar?" }.returns(@response)
@searcher.find(@request)
end
it "should provide an Accept header containing the list of supported formats joined with commas" do
@connection.expects(:get).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response)
@searcher.model.expects(:supported_formats).returns %w{supported formats}
@searcher.find(@request)
end
it "should add Accept-Encoding header" do
@searcher.expects(:add_accept_encoding).returns({"accept-encoding" => "gzip"})
@connection.expects(:get).with { |path, args| args["accept-encoding"] == "gzip" }.returns(@response)
@searcher.find(@request)
end
it "should deserialize and return the network response" do
@searcher.expects(:deserialize).with(@response).returns @instance
@searcher.find(@request).should equal(@instance)
end
it "should set the name of the resulting instance to the asked-for name" do
@searcher.expects(:deserialize).with(@response).returns @instance
@instance.expects(:name=).with "foo bar"
@searcher.find(@request)
end
it "should generate an error when result data deserializes fails" do
@searcher.expects(:deserialize).raises(ArgumentError)
lambda { @searcher.find(@request) }.should raise_error(ArgumentError)
end
end
describe "when doing a head" do
before :each do
@connection = stub('mock http connection', :head => @response, :verify_callback= => nil)
@searcher.stubs(:network).returns(@connection)
# Use a key with spaces, so we can test escaping
@request = Puppet::Indirector::Request.new(:foo, :head, "foo bar")
end
it "should call the HEAD http method on a network connection" do
@searcher.expects(:network).returns @connection
@connection.expects(:head).returns @response
@searcher.head(@request)
end
it "should return true if there was a successful http response" do
@connection.expects(:head).returns @response
@response.stubs(:code).returns "200"
@searcher.head(@request).should == true
end
it "should return false if there was a successful http response" do
@connection.expects(:head).returns @response
@response.stubs(:code).returns "404"
@searcher.head(@request).should == false
end
it "should use the URI generated by the Handler module" do
@searcher.expects(:indirection2uri).with(@request).returns "/my/uri"
@connection.expects(:head).with { |path, args| path == "/my/uri" }.returns(@response)
@searcher.head(@request)
end
end
describe "when doing a search" do
before :each do
@connection = stub('mock http connection', :get => @response, :verify_callback= => nil)
@searcher.stubs(:network).returns(@connection) # neuter the network connection
@model.stubs(:convert_from_multiple)
@request = Puppet::Indirector::Request.new(:foo, :search, "foo bar")
end
it "should call the GET http method on a network connection" do
@searcher.expects(:network).returns @connection
@connection.expects(:get).returns @response
@searcher.search(@request)
end
it "should deserialize as multiple instances and return the http response" do
@connection.expects(:get).returns @response
@searcher.expects(:deserialize).with(@response, true).returns "myobject"
@searcher.search(@request).should == 'myobject'
end
it "should use the URI generated by the Handler module" do
@searcher.expects(:indirection2uri).with(@request).returns "/mys/uri"
@connection.expects(:get).with { |path, args| path == "/mys/uri" }.returns(@response)
@searcher.search(@request)
end
it "should provide an Accept header containing the list of supported formats joined with commas" do
@connection.expects(:get).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response)
@searcher.model.expects(:supported_formats).returns %w{supported formats}
@searcher.search(@request)
end
it "should return an empty array if serialization returns nil" do
@model.stubs(:convert_from_multiple).returns nil
@searcher.search(@request).should == []
end
it "should generate an error when result data deserializes fails" do
@searcher.expects(:deserialize).raises(ArgumentError)
lambda { @searcher.search(@request) }.should raise_error(ArgumentError)
end
end
describe "when doing a destroy" do
before :each do
@connection = stub('mock http connection', :delete => @response, :verify_callback= => nil)
@searcher.stubs(:network).returns(@connection) # neuter the network connection
@request = Puppet::Indirector::Request.new(:foo, :destroy, "foo bar")
end
it "should call the DELETE http method on a network connection" do
@searcher.expects(:network).returns @connection
@connection.expects(:delete).returns @response
@searcher.destroy(@request)
end
it "should fail if any options are provided, since DELETE apparently does not support query options" do
@request.stubs(:options).returns(:one => "two", :three => "four")
lambda { @searcher.destroy(@request) }.should raise_error(ArgumentError)
end
it "should deserialize and return the http response" do
@connection.expects(:delete).returns @response
@searcher.expects(:deserialize).with(@response).returns "myobject"
@searcher.destroy(@request).should == 'myobject'
end
it "should use the URI generated by the Handler module" do
@searcher.expects(:indirection2uri).with(@request).returns "/my/uri"
@connection.expects(:delete).with { |path, args| path == "/my/uri" }.returns(@response)
@searcher.destroy(@request)
end
it "should not include the query string" do
@connection.stubs(:delete).returns @response
@searcher.destroy(@request)
end
it "should provide an Accept header containing the list of supported formats joined with commas" do
@connection.expects(:delete).with { |path, args| args["Accept"] == "supported, formats" }.returns(@response)
@searcher.model.expects(:supported_formats).returns %w{supported formats}
@searcher.destroy(@request)
end
it "should deserialize and return the network response" do
@searcher.expects(:deserialize).with(@response).returns @instance
@searcher.destroy(@request).should equal(@instance)
end
it "should generate an error when result data deserializes fails" do
@searcher.expects(:deserialize).raises(ArgumentError)
lambda { @searcher.destroy(@request) }.should raise_error(ArgumentError)
end
end
describe "when doing a save" do
before :each do
@connection = stub('mock http connection', :put => @response, :verify_callback= => nil)
@searcher.stubs(:network).returns(@connection) # neuter the network connection
@instance = stub 'instance', :render => "mydata", :mime => "mime"
@request = Puppet::Indirector::Request.new(:foo, :save, "foo bar")
@request.instance = @instance
end
it "should call the PUT http method on a network connection" do
@searcher.expects(:network).returns @connection
@connection.expects(:put).returns @response
@searcher.save(@request)
end
it "should fail if any options are provided, since DELETE apparently does not support query options" do
@request.stubs(:options).returns(:one => "two", :three => "four")
lambda { @searcher.save(@request) }.should raise_error(ArgumentError)
end
it "should use the URI generated by the Handler module" do
@searcher.expects(:indirection2uri).with(@request).returns "/my/uri"
@connection.expects(:put).with { |path, args| path == "/my/uri" }.returns(@response)
@searcher.save(@request)
end
it "should serialize the instance using the default format and pass the result as the body of the request" do
@instance.expects(:render).returns "serial_instance"
@connection.expects(:put).with { |path, data, args| data == "serial_instance" }.returns @response
@searcher.save(@request)
end
it "should deserialize and return the http response" do
@connection.expects(:put).returns @response
@searcher.expects(:deserialize).with(@response).returns "myobject"
@searcher.save(@request).should == 'myobject'
end
it "should provide an Accept header containing the list of supported formats joined with commas" do
@connection.expects(:put).with { |path, data, args| args["Accept"] == "supported, formats" }.returns(@response)
@searcher.model.expects(:supported_formats).returns %w{supported formats}
@searcher.save(@request)
end
it "should provide a Content-Type header containing the mime-type of the sent object" do
@connection.expects(:put).with { |path, data, args| args['Content-Type'] == "mime" }.returns(@response)
@instance.expects(:mime).returns "mime"
@searcher.save(@request)
end
it "should deserialize and return the network response" do
@searcher.expects(:deserialize).with(@response).returns @instance
@searcher.save(@request).should equal(@instance)
end
it "should generate an error when result data deserializes fails" do
@searcher.expects(:deserialize).raises(ArgumentError)
lambda { @searcher.save(@request) }.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/unit/network/handler/ca_spec.rb b/spec/unit/network/handler/ca_spec.rb
new file mode 100644
index 000000000..43aa5a721
--- /dev/null
+++ b/spec/unit/network/handler/ca_spec.rb
@@ -0,0 +1,86 @@
+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/xmlrpc/client_spec.rb b/spec/unit/network/xmlrpc/client_spec.rb
deleted file mode 100755
index b9be0a906..000000000
--- a/spec/unit/network/xmlrpc/client_spec.rb
+++ /dev/null
@@ -1,172 +0,0 @@
-#!/usr/bin/env rspec
-require 'puppet/network/client'
-
-require 'spec_helper'
-
-describe Puppet::Network::XMLRPCClient do
- describe "when performing the rpc call" do
- before do
- Puppet::SSL::Host.any_instance.stubs(:certificate_matches_key?).returns true
- @client = Puppet::Network::Client.report.xmlrpc_client.new
- @client.stubs(:call).returns "foo"
- end
-
- it "should call the specified namespace and method, with the specified arguments" do
- @client.expects(:call).with("puppetreports.report", "eh").returns "foo"
- @client.report("eh")
- end
-
- it "should return the results from the call" do
- @client.expects(:call).returns "foo"
- @client.report("eh").should == "foo"
- end
-
- it "should always close the http connection if it is still open after the call" do
- http = mock 'http'
- @client.stubs(:http).returns http
-
- http.expects(:started?).returns true
- http.expects(:finish)
-
- @client.report("eh").should == "foo"
- end
-
- it "should always close the http connection if it is still open after a call that raises an exception" do
- http = mock 'http'
- @client.stubs(:http).returns http
-
- @client.expects(:call).raises RuntimeError
-
- http.expects(:started?).returns true
- http.expects(:finish)
-
- lambda { @client.report("eh") }.should raise_error
- end
-
- describe "when returning the http instance" do
- it "should use the http pool to create the instance" do
- @client.instance_variable_set("@http", nil)
- @client.expects(:host).returns "myhost"
- @client.expects(:port).returns "myport"
- Puppet::Network::HttpPool.expects(:http_instance).with("myhost", "myport", true).returns "http"
-
- @client.http.should == "http"
- end
-
- it "should reuse existing instances" do
- @client.http.should equal(@client.http)
- end
- end
-
- describe "when recycling the connection" do
- it "should close the existing instance if it's open" do
- http = mock 'http'
- @client.stubs(:http).returns http
-
- http.expects(:started?).returns true
- http.expects(:finish)
-
- @client.recycle_connection
- end
-
- it "should force creation of a new instance" do
- Puppet::Network::HttpPool.expects(:http_instance).returns "second_http"
-
- @client.recycle_connection
-
- @client.http.should == "second_http"
- end
- end
-
- describe "and an exception is raised" do
- it "should raise XMLRPCClientError if XMLRPC::FaultException is raised" do
- error = XMLRPC::FaultException.new("foo", "bar")
-
- @client.expects(:call).raises(error)
-
- lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
- end
-
- it "should raise XMLRPCClientError if Errno::ECONNREFUSED is raised" do
- @client.expects(:call).raises(Errno::ECONNREFUSED)
-
- lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
- end
-
- it "should log and raise XMLRPCClientError if Timeout::Error is raised" do
- Puppet.expects(:err)
- @client.expects(:call).raises(Timeout::Error)
-
- lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
- end
-
- it "should log and raise XMLRPCClientError if SocketError is raised" do
- Puppet.expects(:err)
- @client.expects(:call).raises(SocketError)
-
- lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
- end
-
- it "should log, recycle the connection, and retry if Errno::EPIPE is raised" do
- @client.expects(:call).times(2).raises(Errno::EPIPE).then.returns "eh"
-
- Puppet.expects(:info)
- @client.expects(:recycle_connection)
-
- @client.report("eh")
- end
-
- it "should log, recycle the connection, and retry if EOFError is raised" do
- @client.expects(:call).times(2).raises(EOFError).then.returns "eh"
-
- Puppet.expects(:info)
- @client.expects(:recycle_connection)
-
- @client.report("eh")
- end
-
- it "should log and retry if an exception containing 'Wrong size' is raised" do
- error = RuntimeError.new("Wrong size. Was 15, should be 30")
- @client.expects(:call).times(2).raises(error).then.returns "eh"
-
- Puppet.expects(:warning)
-
- @client.report("eh")
- end
-
- it "should raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised" do
- @client.expects(:call).raises(OpenSSL::SSL::SSLError)
-
- lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
- end
-
- it "should log and raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised with certificate issues" do
- error = OpenSSL::SSL::SSLError.new("hostname was not match")
- @client.expects(:call).raises(error)
-
- Puppet.expects(:warning)
-
- lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
- end
-
- it "should log, recycle the connection, and retry if OpenSSL::SSL::SSLError is raised containing 'bad write retry'" do
- error = OpenSSL::SSL::SSLError.new("bad write retry")
- @client.expects(:call).times(2).raises(error).then.returns "eh"
-
- @client.expects(:recycle_connection)
-
- Puppet.expects(:warning)
-
- @client.report("eh")
- end
-
- it "should log and raise XMLRPCClientError if any other exception is raised" do
- @client.expects(:call).raises(RuntimeError)
-
- Puppet.expects(:err)
-
- lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
- end
- end
- end
-end
diff --git a/spec/unit/provider/exec/windows_spec.rb b/spec/unit/provider/exec/windows_spec.rb
old mode 100644
new mode 100755
index f566ad262..28438de56
--- a/spec/unit/provider/exec/windows_spec.rb
+++ b/spec/unit/provider/exec/windows_spec.rb
@@ -1,119 +1,112 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe Puppet::Type.type(:exec).provider(:windows) do
include PuppetSpec::Files
let(:resource) { Puppet::Type.type(:exec).new(:title => 'C:\foo', :provider => :windows) }
let(:provider) { described_class.new(resource) }
before :each do
Puppet.features.stubs(:microsoft_windows?).returns(true)
Puppet.features.stubs(:posix?).returns(false)
end
after :all do
# This provider may not be suitable on some machines, so we want to reset
# the default so it isn't used by mistake in future specs.
Puppet::Type.type(:exec).defaultprovider = nil
end
describe "#extractexe" do
describe "when the command has no arguments" do
it "should return the command if it's quoted" do
provider.extractexe('"foo"').should == 'foo'
end
it "should return the command if it's quoted and contains spaces" do
provider.extractexe('"foo bar"').should == 'foo bar'
end
it "should return the command if it's not quoted" do
provider.extractexe('foo').should == 'foo'
end
end
describe "when the command has arguments" do
it "should return the command if it's quoted" do
provider.extractexe('"foo" bar baz').should == 'foo'
end
it "should return the command if it's quoted and contains spaces" do
provider.extractexe('"foo bar" baz "quux quiz"').should == 'foo bar'
end
it "should return the command if it's not quoted" do
provider.extractexe('foo bar baz').should == 'foo'
end
end
end
describe "#checkexe" do
describe "when the command is absolute", :if => Puppet.features.microsoft_windows? do
it "should return if the command exists and is a file" do
command = tmpfile('command')
FileUtils.touch(command)
provider.checkexe(command).should == nil
end
it "should fail if the command doesn't exist" do
command = tmpfile('command')
expect { provider.checkexe(command) }.to raise_error(ArgumentError, "Could not find command '#{command}'")
end
it "should fail if the command isn't a file" do
command = tmpfile('command')
FileUtils.mkdir(command)
expect { provider.checkexe(command) }.to raise_error(ArgumentError, "'#{command}' is a directory, not a file")
end
end
describe "when the command is relative" do
describe "and a path is specified" do
before :each do
provider.stubs(:which)
end
it "should search for executables with no extension" do
+ provider.resource[:path] = [File.expand_path('/bogus/bin')]
provider.expects(:which).with('foo').returns('foo')
provider.checkexe('foo')
end
- %w[bat com ps1 exe].each do |ext|
- it "should search for executables with the extension '#{ext}'" do
- provider.expects(:which).with("foo.#{ext}").returns("foo.#{ext}")
-
- provider.checkexe('foo')
- end
- end
-
it "should fail if the command isn't in the path" do
expect { provider.checkexe('foo') }.to raise_error(ArgumentError, "Could not find command 'foo'")
end
end
it "should fail if no path is specified" do
expect { provider.checkexe('foo') }.to raise_error(ArgumentError, "Could not find command 'foo'")
end
end
end
describe "#validatecmd" do
it "should fail if the command isn't absolute and there is no path" do
expect { provider.validatecmd('foo') }.to raise_error(Puppet::Error, /'foo' is not qualified and no path was specified/)
end
it "should not fail if the command is absolute and there is no path" do
provider.validatecmd('C:\foo').should == nil
end
it "should not fail if the command is not absolute and there is a path" do
resource[:path] = 'C:\path;C:\another_path'
provider.validatecmd('foo').should == nil
end
end
end
diff --git a/spec/unit/provider/service/launchd_spec.rb b/spec/unit/provider/service/launchd_spec.rb
index 8ae7f003d..c149c7e4f 100755
--- a/spec/unit/provider/service/launchd_spec.rb
+++ b/spec/unit/provider/service/launchd_spec.rb
@@ -1,203 +1,215 @@
-#!/usr/bin/env rspec
-#
-# Unit testing for the launchd service provider
+# Spec Tests for the Launchd provider
#
require 'spec_helper'
-require 'puppet'
-
-provider_class = Puppet::Type.type(:service).provider(:launchd)
-
-describe provider_class do
-
- before :each do
- # Create a mock resource
- @resource = stub 'resource'
-
- @provider = provider_class.new
- @joblabel = "com.foo.food"
- @jobplist = {}
-
- # A catch all; no parameters set
- @resource.stubs(:[]).returns(nil)
-
- # But set name, ensure and enable
- @resource.stubs(:[]).with(:name).returns @joblabel
- @resource.stubs(:[]).with(:ensure).returns :enabled
- @resource.stubs(:[]).with(:enable).returns :true
- @resource.stubs(:ref).returns "Service[#{@joblabel}]"
-
- # stub out the provider methods that actually touch the filesystem
- # or execute commands
- @provider.stubs(:plist_from_label).returns([@joblabel, @jobplist])
- @provider.stubs(:execute).returns("")
- @provider.stubs(:resource).returns @resource
-
- # We stub this out for the normal case as 10.6 is "special".
- provider_class.stubs(:get_macosx_version_major).returns("10.5")
-
- end
-
- it "should have a start method for #{@provider.object_id}" do
- @provider.should respond_to(:start)
- end
-
- it "should have a stop method" do
- @provider.should respond_to(:stop)
- end
+describe Puppet::Type.type(:service).provider(:launchd) do
+ let (:joblabel) { "com.foo.food" }
+ let (:provider) { subject.class }
+ let (:launchd_overrides) { '/var/db/launchd.db/com.apple.launchd/overrides.plist' }
- it "should have an enabled? method" do
- @provider.should respond_to(:enabled?)
- end
-
- it "should have an enable method" do
- @provider.should respond_to(:enable)
- end
-
- it "should have a disable method" do
- @provider.should respond_to(:disable)
- end
-
- it "should have a status method" do
- @provider.should respond_to(:status)
+ describe "the type interface" do
+ %w{ start stop enabled? enable disable status}.each do |method|
+ it { should respond_to method.to_sym }
+ end
end
-
- describe "when checking status" do
+ describe 'the status of the services' do
it "should call the external command 'launchctl list' once" do
- @provider.expects(:launchctl).with(:list).returns("rotating-strawberry-madonnas")
- @provider.status
+ provider.expects(:launchctl).with(:list).returns(joblabel)
+ provider.expects(:jobsearch).with(nil).returns({joblabel => "/Library/LaunchDaemons/#{joblabel}"})
+ provider.prefetch({})
end
it "should return stopped if not listed in launchctl list output" do
- @provider.stubs(:launchctl).with(:list).returns("rotating-strawberry-madonnas")
- @provider.status.should == :stopped
+ provider.expects(:launchctl).with(:list).returns('com.bar.is_running')
+ provider.expects(:jobsearch).with(nil).returns({'com.bar.is_not_running' => "/Library/LaunchDaemons/com.bar.is_not_running"})
+ provider.prefetch({}).last.status.should eq :stopped
end
it "should return running if listed in launchctl list output" do
- @provider.stubs(:launchctl).with(:list).returns(@joblabel)
- @provider.status.should == :running
+ provider.expects(:launchctl).with(:list).returns('com.bar.is_running')
+ provider.expects(:jobsearch).with(nil).returns({'com.bar.is_running' => "/Library/LaunchDaemons/com.bar.is_running"})
+ provider.prefetch({}).last.status.should eq :running
+ end
+ after :each do
+ provider.instance_variable_set(:@job_list, nil)
end
end
- describe "when checking whether the service is enabled" do
- it "should return true if the job plist says disabled is false" do
- @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => false}])
- @provider.enabled?.should == :true
+ describe "when checking whether the service is enabled on OS X 10.5" do
+ it "should return true in if the job plist says disabled is false" do
+ Facter.stubs(:value).with(:macosx_productversion_major).returns('10.5')
+ Facter.stubs(:value).with(:kernel).returns('Darwin')
+ Facter.stubs(:value).with(:macaddress).returns('')
+ Facter.stubs(:value).with(:arp).returns('')
+ subject.expects(:plist_from_label).with(joblabel).returns(["foo", {"Disabled" => false}])
+ subject.expects(:resource).returns({:name => joblabel})
+ subject.enabled?.should == :true
end
- it "should return true if the job plist has no disabled key" do
- @provider.stubs(:plist_from_label).returns(["foo", {}])
- @provider.enabled?.should == :true
+ it "should return true in if the job plist has no disabled key" do
+ subject.expects(:resource).returns({:name => joblabel})
+ subject.stubs(:plist_from_label).returns(["foo", {}])
+ subject.enabled?.should == :true
end
- it "should return false if the job plist says disabled is true" do
- @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => true}])
- @provider.enabled?.should == :false
+ it "should return false in if the job plist says disabled is true" do
+ subject.expects(:resource).returns({:name => joblabel})
+ subject.stubs(:plist_from_label).returns(["foo", {"Disabled" => true}])
+ subject.enabled?.should == :false
end
end
describe "when checking whether the service is enabled on OS X 10.6" do
it "should return true if the job plist says disabled is true and the global overrides says disabled is false" do
- provider_class.stubs(:get_macosx_version_major).returns("10.6")
- @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => true}])
- @provider.class.stubs(:read_plist).returns({@resource[:name] => {"Disabled" => false}})
- FileTest.expects(:file?).with(Launchd_Overrides).returns(true)
- @provider.enabled?.should == :true
+ provider.expects(:get_macosx_version_major).returns("10.6")
+ subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => true}])
+ provider.stubs(:read_plist).returns({joblabel => {"Disabled" => false}})
+ FileTest.expects(:file?).with(launchd_overrides).returns(true)
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.enabled?.should == :true
end
it "should return false if the job plist says disabled is false and the global overrides says disabled is true" do
- provider_class.stubs(:get_macosx_version_major).returns("10.6")
- @provider.stubs(:plist_from_label).returns(["foo", {"Disabled" => false}])
- @provider.class.stubs(:read_plist).returns({@resource[:name] => {"Disabled" => true}})
- FileTest.expects(:file?).with(Launchd_Overrides).returns(true)
- @provider.enabled?.should == :false
+ provider.expects(:get_macosx_version_major).returns("10.6")
+ subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => false}])
+ provider.stubs(:read_plist).returns({joblabel => {"Disabled" => true}})
+ FileTest.expects(:file?).with(launchd_overrides).returns(true)
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.enabled?.should == :false
end
it "should return true if the job plist and the global overrides have no disabled keys" do
- provider_class.stubs(:get_macosx_version_major).returns("10.6")
- @provider.stubs(:plist_from_label).returns(["foo", {}])
- @provider.class.stubs(:read_plist).returns({})
- FileTest.expects(:file?).with(Launchd_Overrides).returns(true)
- @provider.enabled?.should == :true
+ provider.expects(:get_macosx_version_major).returns("10.6")
+ subject.expects(:plist_from_label).returns([joblabel, {}])
+ provider.stubs(:read_plist).returns({})
+ FileTest.expects(:file?).with(launchd_overrides).returns(true)
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.enabled?.should == :true
end
end
describe "when starting the service" do
it "should look for the relevant plist once" do
- @provider.expects(:plist_from_label).once
- @provider.start
- end
- it "should execute 'launchctl load' once without writing to the plist if the job is enabled" do
- @provider.stubs(:enabled?).returns :true
- @provider.expects(:execute).with([:launchctl, :load, @resource[:name]]).once
- @provider.start
+ subject.expects(:plist_from_label).returns([joblabel, {}]).once
+ subject.stubs(:enabled?).returns :true
+ subject.stubs(:execute).with([:launchctl, :load, joblabel])
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.start
+ end
+ it "should execute 'launchctl load' once without writing to the plist if the job is enabled" do
+ subject.stubs(:plist_from_label).returns([joblabel, {}])
+ subject.stubs(:enabled?).returns :true
+ subject.expects(:execute).with([:launchctl, :load, joblabel]).once
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.start
end
it "should execute 'launchctl load' with writing to the plist once if the job is disabled" do
- @provider.stubs(:enabled?).returns :false
- @provider.expects(:execute).with([:launchctl, :load, "-w", @resource[:name]]).once
- @provider.start
+ subject.stubs(:plist_from_label).returns([joblabel, {}])
+ subject.stubs(:enabled?).returns(:false)
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.expects(:execute).with([:launchctl, :load, "-w", joblabel]).once
+ subject.start
end
it "should disable the job once if the job is disabled and should be disabled at boot" do
- @provider.stubs(:enabled?).returns :false
- @resource.stubs(:[]).with(:enable).returns :false
- @provider.expects(:disable).once
- @provider.start
+ subject.stubs(:plist_from_label).returns([joblabel, {"Disabled" => true}])
+ subject.stubs(:enabled?).returns :false
+ subject.stubs(:execute).with([:launchctl, :load, "-w", joblabel])
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :false})
+ subject.expects(:disable).once
+ subject.start
end
end
describe "when stopping the service" do
it "should look for the relevant plist once" do
- @provider.expects(:plist_from_label).once
- @provider.stop
+ subject.expects(:plist_from_label).returns([joblabel, {}]).once
+ subject.stubs(:enabled?).returns :true
+ subject.stubs(:execute).with([:launchctl, :unload, '-w', joblabel])
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.stop
end
it "should execute 'launchctl unload' once without writing to the plist if the job is disabled" do
- @provider.stubs(:enabled?).returns :false
- @provider.expects(:execute).with([:launchctl, :unload, @resource[:name]]).once
- @provider.stop
+ subject.stubs(:plist_from_label).returns([joblabel, {}])
+ subject.stubs(:enabled?).returns :false
+ subject.expects(:execute).with([:launchctl, :unload, joblabel]).once
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.stop
end
it "should execute 'launchctl unload' with writing to the plist once if the job is enabled" do
- @provider.stubs(:enabled?).returns :true
- @provider.expects(:execute).with([:launchctl, :unload, "-w", @resource[:name]]).once
- @provider.stop
+ subject.stubs(:plist_from_label).returns([joblabel, {}])
+ subject.stubs(:enabled?).returns :true
+ subject.expects(:execute).with([:launchctl, :unload, '-w', joblabel]).once
+ subject.stubs(:resource).returns({:name => joblabel})
+ subject.stop
end
it "should enable the job once if the job is enabled and should be enabled at boot" do
- @provider.stubs(:enabled?).returns :true
- @resource.stubs(:[]).with(:enable).returns :true
- @provider.expects(:enable).once
- @provider.stop
+ subject.stubs(:plist_from_label).returns([joblabel, {"Disabled" => false}])
+ subject.stubs(:enabled?).returns :true
+ subject.stubs(:execute).with([:launchctl, :unload, "-w", joblabel])
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :true})
+ subject.expects(:enable).once
+ subject.stop
end
end
describe "when enabling the service" do
- it "should look for the relevant plist once" do
- @provider.expects(:plist_from_label).once
- @provider.stop
+ it "should look for the relevant plist once" do ### Do we need this test? Differentiating it?
+ subject.expects(:plist_from_label).returns([joblabel, {}]).once
+ subject.stubs(:enabled?).returns :false
+ subject.stubs(:execute).with([:launchctl, :unload, joblabel])
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :true})
+ subject.stop
end
it "should check if the job is enabled once" do
- @provider.expects(:enabled?).once
- @provider.stop
+ subject.stubs(:plist_from_label).returns([joblabel, {}]).once
+ subject.expects(:enabled?).once
+ subject.stubs(:execute).with([:launchctl, :unload, joblabel])
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :true})
+ subject.stop
end
end
describe "when disabling the service" do
it "should look for the relevant plist once" do
- @provider.expects(:plist_from_label).once
- @provider.stop
+ subject.expects(:plist_from_label).returns([joblabel, {}]).once
+ subject.stubs(:enabled?).returns :true
+ subject.stubs(:execute).with([:launchctl, :unload, '-w', joblabel])
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :false})
+ subject.stop
end
end
describe "when enabling the service on OS X 10.6" do
it "should write to the global launchd overrides file once" do
- provider_class.stubs(:get_macosx_version_major).returns("10.6")
- @provider.class.stubs(:read_plist).returns({})
+ provider.stubs(:get_macosx_version_major).returns("10.6")
+ provider.stubs(:read_plist).returns({})
Plist::Emit.expects(:save_plist).once
- @provider.enable
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :true})
+ subject.enable
end
end
describe "when disabling the service on OS X 10.6" do
it "should write to the global launchd overrides file once" do
- provider_class.stubs(:get_macosx_version_major).returns("10.6")
- @provider.class.stubs(:read_plist).returns({})
+ provider.stubs(:get_macosx_version_major).returns("10.6")
+ provider.stubs(:read_plist).returns({})
Plist::Emit.expects(:save_plist).once
- @provider.enable
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :false})
+ subject.enable
end
end
-end
+ describe "when using an incompatible version of Facter" do
+ before :each do
+ provider.instance_variable_set(:@macosx_version_major, nil)
+ end
+ it "should display a deprecation warning" do
+ Facter.stubs(:value).with(:macosx_productversion_major).returns(nil)
+ Facter.stubs(:value).with(:kernel).returns('Darwin')
+ Facter.stubs(:value).with(:macosx_productversion).returns('10.5.8')
+ Puppet::Util::Warnings.expects(:maybe_log)
+ provider.stubs(:read_plist).returns({joblabel => {"Disabled" => false}})
+ subject.stubs(:plist_from_label).returns([joblabel, {"Disabled" => false}])
+ subject.stubs(:enabled?).returns :false
+ subject.stubs(:execute).with([:launchctl, :load, '-w', joblabel])
+ subject.stubs(:resource).returns({:name => joblabel, :enable => :true})
+ subject.enable
+ end
+ end
+end
\ No newline at end of file
diff --git a/spec/unit/provider/user/user_role_add_spec.rb b/spec/unit/provider/user/user_role_add_spec.rb
index 5f2fc306e..afcefa58b 100755
--- a/spec/unit/provider/user/user_role_add_spec.rb
+++ b/spec/unit/provider/user/user_role_add_spec.rb
@@ -1,266 +1,296 @@
#!/usr/bin/env rspec
require 'spec_helper'
+require 'puppet_spec/files'
provider_class = Puppet::Type.type(:user).provider(:user_role_add)
describe provider_class do
+ include PuppetSpec::Files
+
before do
@resource = stub("resource", :name => "myuser", :managehome? => nil)
@resource.stubs(:should).returns "fakeval"
@resource.stubs(:[]).returns "fakeval"
@resource.stubs(:allowdupe?).returns false
@provider = provider_class.new(@resource)
end
describe "when calling command" do
before do
klass = stub("provider")
klass.stubs(:command).with(:foo).returns("userfoo")
klass.stubs(:command).with(:role_foo).returns("rolefoo")
@provider.stubs(:class).returns(klass)
end
it "should use the command if not a role and ensure!=role" do
@provider.stubs(:is_role?).returns(false)
@provider.stubs(:exists?).returns(false)
@resource.stubs(:[]).with(:ensure).returns(:present)
@provider.command(:foo).should == "userfoo"
end
it "should use the role command when a role" do
@provider.stubs(:is_role?).returns(true)
@provider.command(:foo).should == "rolefoo"
end
it "should use the role command when !exists and ensure=role" do
@provider.stubs(:is_role?).returns(false)
@provider.stubs(:exists?).returns(false)
@resource.stubs(:[]).with(:ensure).returns(:role)
@provider.command(:foo).should == "rolefoo"
end
end
describe "when calling transition", :'fails_on_ruby_1.9.2' => true do
it "should return the type set to whatever is passed in" do
@provider.expects(:command).with(:modify).returns("foomod")
@provider.transition("bar").include?("type=bar")
end
end
describe "when calling create" do
before do
@provider.stubs(:password=)
end
it "should use the add command when the user is not a role" do
@provider.stubs(:is_role?).returns(false)
@provider.expects(:addcmd).returns("useradd")
@provider.expects(:run).at_least_once
@provider.create
end
it "should use transition(normal) when the user is a role" do
@provider.stubs(:is_role?).returns(true)
@provider.expects(:transition).with("normal")
@provider.expects(:run)
@provider.create
end
it "should set password age rules" do
@resource = Puppet::Type.type(:user).new :name => "myuser", :password_min_age => 5, :password_max_age => 10, :provider => :user_role_add
@provider = provider_class.new(@resource)
@provider.stubs(:user_attributes)
@provider.stubs(:execute)
@provider.expects(:execute).with { |cmd, *args| args == ["-n", 5, "-x", 10, "myuser"] }
@provider.create
end
end
describe "when calling destroy" do
it "should use the delete command if the user exists and is not a role" do
@provider.stubs(:exists?).returns(true)
@provider.stubs(:is_role?).returns(false)
@provider.expects(:deletecmd)
@provider.expects(:run)
@provider.destroy
end
it "should use the delete command if the user is a role" do
@provider.stubs(:exists?).returns(true)
@provider.stubs(:is_role?).returns(true)
@provider.expects(:deletecmd)
@provider.expects(:run)
@provider.destroy
end
end
describe "when calling create_role" do
it "should use the transition(role) if the user exists" do
@provider.stubs(:exists?).returns(true)
@provider.stubs(:is_role?).returns(false)
@provider.expects(:transition).with("role")
@provider.expects(:run)
@provider.create_role
end
it "should use the add command when role doesn't exists" do
@provider.stubs(:exists?).returns(false)
@provider.expects(:addcmd)
@provider.expects(:run)
@provider.create_role
end
end
describe "when allow duplicate is enabled" do
before do
@resource.expects(:allowdupe?).returns true
@resource.stubs(:system?)
@provider.stubs(:is_role?).returns(false)
@provider.stubs(:execute)
@provider.expects(:execute).with { |args| args.include?("-o") }
end
it "should add -o when the user is being created", :'fails_on_ruby_1.9.2' => true do
@provider.stubs(:password=)
@provider.create
end
it "should add -o when the uid is being modified" do
@provider.uid = 150
end
end
[:roles, :auths, :profiles].each do |val|
describe "when getting #{val}" do
it "should get the user_attributes" do
@provider.expects(:user_attributes)
@provider.send(val)
end
it "should get the #{val} attribute" do
attributes = mock("attributes")
attributes.expects(:[]).with(val)
@provider.stubs(:user_attributes).returns(attributes)
@provider.send(val)
end
end
end
describe "when getting the keys" do
it "should get the user_attributes" do
@provider.expects(:user_attributes)
@provider.keys
end
it "should call removed_managed_attributes" do
@provider.stubs(:user_attributes).returns({ :type => "normal", :foo => "something" })
@provider.expects(:remove_managed_attributes)
@provider.keys
end
it "should removed managed attribute (type, auths, roles, etc)" do
@provider.stubs(:user_attributes).returns({ :type => "normal", :foo => "something" })
@provider.keys.should == { :foo => "something" }
end
end
describe "when adding properties" do
it "should call build_keys_cmd" do
@resource.stubs(:should).returns ""
@resource.expects(:should).with(:keys).returns({ :foo => "bar" })
@provider.expects(:build_keys_cmd).returns([])
@provider.add_properties
end
it "should add the elements of the keys hash to an array" do
@resource.stubs(:should).returns ""
@resource.expects(:should).with(:keys).returns({ :foo => "bar"})
@provider.add_properties.must == ["-K", "foo=bar"]
end
end
describe "when calling build_keys_cmd" do
it "should build cmd array with keypairs seperated by -K ending with user" do
@provider.build_keys_cmd({"foo" => "bar", "baz" => "boo"}).should.eql? ["-K", "foo=bar", "-K", "baz=boo"]
end
end
describe "when setting the keys" do
before do
@provider.stubs(:is_role?).returns(false)
end
it "should run a command" do
@provider.expects(:run)
@provider.keys=({})
end
it "should build the command" do
@resource.stubs(:[]).with(:name).returns("someuser")
@provider.stubs(:command).returns("usermod")
@provider.expects(:build_keys_cmd).returns(["-K", "foo=bar"])
@provider.expects(:run).with(["usermod", "-K", "foo=bar", "someuser"], "modify attribute key pairs")
@provider.keys=({})
end
end
describe "when getting the hashed password" do
before do
@array = mock "array"
end
it "should readlines of /etc/shadow" do
File.expects(:readlines).with("/etc/shadow").returns([])
@provider.password
end
it "should reject anything that doesn't start with alpha numerics" do
@array.expects(:reject).returns([])
File.stubs(:readlines).with("/etc/shadow").returns(@array)
@provider.password
end
it "should collect splitting on ':'" do
@array.stubs(:reject).returns(@array)
@array.expects(:collect).returns([])
File.stubs(:readlines).with("/etc/shadow").returns(@array)
@provider.password
end
it "should find the matching user" do
@resource.stubs(:[]).with(:name).returns("username")
@array.stubs(:reject).returns(@array)
@array.stubs(:collect).returns([["username", "hashedpassword"], ["someoneelse", "theirpassword"]])
File.stubs(:readlines).with("/etc/shadow").returns(@array)
@provider.password.must == "hashedpassword"
end
it "should get the right password" do
@resource.stubs(:[]).with(:name).returns("username")
File.stubs(:readlines).with("/etc/shadow").returns(["#comment", " nonsense", " ", "username:hashedpassword:stuff:foo:bar:::", "other:pword:yay:::"])
@provider.password.must == "hashedpassword"
end
end
describe "when setting the password" do
- #how can you mock these blocks up?
- it "should open /etc/shadow for reading and /etc/shadow_tmp for writing" do
- File.expects(:open).with("/etc/shadow", "r")
+ before :each do
+ @shadow_file = tmpfile('shadow')
+ File.open(@shadow_file, 'w') do |f|
+ f.puts 'fakeval:password:0'
+ end
+ @provider.stubs(:shadow_file).returns(@shadow_file)
+ end
+
+ it 'opens #shadow_file for reading' do
+ File.expects(:open).with(@shadow_file, "r")
File.stubs(:rename)
- @provider.password=("hashedpassword")
+
+ @provider.password = "hashedpassword"
end
- it "should rename the /etc/shadow_tmp to /etc/shadow" do
- File.stubs(:open).with("/etc/shadow", "r")
- File.expects(:rename).with("/etc/shadow_tmp", "/etc/shadow")
- @provider.password=("hashedpassword")
+ it 'writes to "#{shadow_file}_tmp"' do
+ File.stubs(:rename)
+ File.stubs(:unlink)
+ @provider.password = 'hashedpassword'
+
+ File.read("#{@shadow_file}_tmp").should =~ /hashedpassword/
+ end
+
+ it 'renames "#{shadow_file}_tmp" to shadow_file' do
+ File.stubs(:open)
+ File.expects(:rename).with("#{@shadow_file}_tmp", @shadow_file)
+
+ @provider.password = "hashedpassword"
+ end
+
+ it 'updates the last changed field' do
+ Time.stubs(:now).returns(42 * 86400)
+
+ File.read(@shadow_file).should == "fakeval:password:0\n"
+
+ @provider.password = 'hashedpassword'
+
+ File.read(@shadow_file).should == "fakeval:hashedpassword:42"
end
end
describe "#shadow_entry" do
it "should return the line for the right user" do
File.stubs(:readlines).returns(["someuser:!:10:5:20:7:1::\n", "fakeval:*:20:10:30:7:2::\n", "testuser:*:30:15:40:7:3::\n"])
@provider.shadow_entry.should == ["fakeval", "*", "20", "10", "30", "7", "2"]
end
end
end
diff --git a/spec/unit/ssl/certificate_authority/interface_spec.rb b/spec/unit/ssl/certificate_authority/interface_spec.rb
index 46273ccee..41a57b822 100755
--- a/spec/unit/ssl/certificate_authority/interface_spec.rb
+++ b/spec/unit/ssl/certificate_authority/interface_spec.rb
@@ -1,332 +1,375 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/ssl/certificate_authority'
shared_examples_for "a normal interface method" do
it "should call the method on the CA for each host specified if an array was provided" do
@ca.expects(@method).with("host1")
@ca.expects(@method).with("host2")
@applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :to => %w{host1 host2})
@applier.apply(@ca)
end
it "should call the method on the CA for all existing certificates if :all was provided" do
@ca.expects(:list).returns %w{host1 host2}
@ca.expects(@method).with("host1")
@ca.expects(@method).with("host2")
@applier = Puppet::SSL::CertificateAuthority::Interface.new(@method, :to => :all)
@applier.apply(@ca)
end
end
describe Puppet::SSL::CertificateAuthority::Interface do
before do
@class = Puppet::SSL::CertificateAuthority::Interface
end
describe "when initializing" do
it "should set its method using its settor" do
- @class.any_instance.expects(:method=).with(:generate)
- @class.new(:generate, :to => :all)
+ instance = @class.new(:generate, :to => :all)
+ instance.method.should == :generate
end
it "should set its subjects using the settor" do
- @class.any_instance.expects(:subjects=).with(:all)
- @class.new(:generate, :to => :all)
+ instance = @class.new(:generate, :to => :all)
+ instance.subjects.should == :all
end
it "should set the digest if given" do
interface = @class.new(:generate, :to => :all, :digest => :digest)
interface.digest.should == :digest
end
it "should set the digest to md5 if none given" do
interface = @class.new(:generate, :to => :all)
interface.digest.should == :MD5
end
end
describe "when setting the method" do
it "should set the method" do
- @class.new(:generate, :to => :all).method.should == :generate
+ instance = @class.new(:generate, :to => :all)
+ instance.method = :list
+
+ instance.method.should == :list
end
it "should fail if the method isn't a member of the INTERFACE_METHODS array" do
- Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.expects(:include?).with(:thing).returns false
-
- lambda { @class.new(:thing, :to => :all) }.should raise_error(ArgumentError)
+ lambda { @class.new(:thing, :to => :all) }.should raise_error(ArgumentError, /Invalid method thing to apply/)
end
end
describe "when setting the subjects" do
it "should set the subjects" do
- @class.new(:generate, :to => :all).subjects.should == :all
+ instance = @class.new(:generate, :to => :all)
+ instance.subjects = :signed
+
+ instance.subjects.should == :signed
end
- it "should fail if the subjects setting isn't :all or an array", :'fails_on_ruby_1.9.2' => true do
- lambda { @class.new(:generate, "other") }.should raise_error(ArgumentError)
+ it "should fail if the subjects setting isn't :all or an array" do
+ lambda { @class.new(:generate, :to => "other") }.should raise_error(ArgumentError, /Subjects must be an array or :all; not other/)
end
end
it "should have a method for triggering the application" do
@class.new(:generate, :to => :all).should respond_to(:apply)
end
describe "when applying" do
before do
# We use a real object here, because :verify can't be stubbed, apparently.
@ca = Object.new
end
it "should raise InterfaceErrors" do
@applier = @class.new(:revoke, :to => :all)
@ca.expects(:list).raises Puppet::SSL::CertificateAuthority::Interface::InterfaceError
lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError)
end
it "should log non-Interface failures rather than failing" do
@applier = @class.new(:revoke, :to => :all)
@ca.expects(:list).raises ArgumentError
Puppet.expects(:err)
lambda { @applier.apply(@ca) }.should_not raise_error
end
describe "with an empty array specified and the method is not list" do
it "should fail" do
@applier = @class.new(:sign, :to => [])
lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
end
end
describe ":generate" do
it "should fail if :all was specified" do
@applier = @class.new(:generate, :to => :all)
lambda { @applier.apply(@ca) }.should raise_error(ArgumentError)
end
it "should call :generate on the CA for each host specified" do
@applier = @class.new(:generate, :to => %w{host1 host2})
- @ca.expects(:generate).with("host1")
- @ca.expects(:generate).with("host2")
+ @ca.expects(:generate).with("host1", {})
+ @ca.expects(:generate).with("host2", {})
@applier.apply(@ca)
end
end
describe ":verify" do
before { @method = :verify }
#it_should_behave_like "a normal interface method"
it "should call the method on the CA for each host specified if an array was provided" do
# LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life.
end
it "should call the method on the CA for all existing certificates if :all was provided" do
# LAK:NOTE Mocha apparently doesn't allow you to mock :verify, but I'm confident this works in real life.
end
end
describe ":destroy" do
before { @method = :destroy }
it_should_behave_like "a normal interface method"
end
describe ":revoke" do
before { @method = :revoke }
it_should_behave_like "a normal interface method"
end
describe ":sign" do
describe "and an array of names was provided" do
- before do
- @applier = @class.new(:sign, :to => %w{host1 host2})
- end
+ let(:applier) { @class.new(:sign, @options.merge(:to => %w{host1 host2})) }
it "should sign the specified waiting certificate requests" do
- @ca.expects(:sign).with("host1")
- @ca.expects(:sign).with("host2")
+ @options = {:allow_dns_alt_names => false}
- @applier.apply(@ca)
+ @ca.expects(:sign).with("host1", false)
+ @ca.expects(:sign).with("host2", false)
+
+ applier.apply(@ca)
+ end
+
+ it "should sign the certificate requests with alt names if specified" do
+ @options = {:allow_dns_alt_names => true}
+
+ @ca.expects(:sign).with("host1", true)
+ @ca.expects(:sign).with("host2", true)
+
+ applier.apply(@ca)
end
end
describe "and :all was provided" do
it "should sign all waiting certificate requests" do
@ca.stubs(:waiting?).returns(%w{cert1 cert2})
- @ca.expects(:sign).with("cert1")
- @ca.expects(:sign).with("cert2")
+ @ca.expects(:sign).with("cert1", nil)
+ @ca.expects(:sign).with("cert2", nil)
@applier = @class.new(:sign, :to => :all)
@applier.apply(@ca)
end
it "should fail if there are no waiting certificate requests" do
@ca.stubs(:waiting?).returns([])
@applier = @class.new(:sign, :to => :all)
lambda { @applier.apply(@ca) }.should raise_error(Puppet::SSL::CertificateAuthority::Interface::InterfaceError)
end
end
end
describe ":list" do
- describe "and an empty array was provided" do
- it "should print a string containing all certificate requests" do
- @ca.expects(:waiting?).returns %w{host1 host2}
- @ca.stubs(:verify)
+ before :each do
+ @cert = Puppet::SSL::Certificate.new 'foo'
+ @csr = Puppet::SSL::CertificateRequest.new 'bar'
- @applier = @class.new(:list, :to => [])
+ @cert.stubs(:subject_alt_names).returns []
+ @csr.stubs(:subject_alt_names).returns []
- @applier.expects(:puts).with "host1\nhost2"
+ Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert
+ Puppet::SSL::CertificateRequest.indirection.stubs(:find).returns @csr
- @applier.apply(@ca)
+ @ca.expects(:waiting?).returns %w{host1 host2 host3}
+ @ca.expects(:list).returns %w{host4 host5 host6}
+ @ca.stubs(:fingerprint).returns "fingerprint"
+ @ca.stubs(:verify)
+ end
+
+ describe "and an empty array was provided" do
+ it "should print all certificate requests" do
+ applier = @class.new(:list, :to => [])
+
+ applier.expects(:puts).with(<<-OUTPUT.chomp)
+ host1 (fingerprint)
+ host2 (fingerprint)
+ host3 (fingerprint)
+ OUTPUT
+
+ applier.apply(@ca)
end
end
describe "and :all was provided" do
it "should print a string containing all certificate requests and certificates" do
- @ca.expects(:waiting?).returns %w{host1 host2}
- @ca.expects(:list).returns %w{host3 host4}
- @ca.stubs(:verify)
- @ca.stubs(:fingerprint).returns "fingerprint"
- @ca.expects(:verify).with("host3").raises(Puppet::SSL::CertificateAuthority::CertificateVerificationError.new(23), "certificate revoked")
+ @ca.stubs(:verify).with("host4").raises(Puppet::SSL::CertificateAuthority::CertificateVerificationError.new(23), "certificate revoked")
- @applier = @class.new(:list, :to => :all)
+ applier = @class.new(:list, :to => :all)
- @applier.expects(:puts).with "host1 (fingerprint)"
- @applier.expects(:puts).with "host2 (fingerprint)"
- @applier.expects(:puts).with "- host3 (fingerprint) (certificate revoked)"
- @applier.expects(:puts).with "+ host4 (fingerprint)"
+ applier.expects(:puts).with(<<-OUTPUT.chomp)
+ host1 (fingerprint)
+ host2 (fingerprint)
+ host3 (fingerprint)
++ host5 (fingerprint)
++ host6 (fingerprint)
+- host4 (fingerprint) (certificate revoked)
+ OUTPUT
- @applier.apply(@ca)
+ applier.apply(@ca)
end
end
describe "and :signed was provided" do
it "should print a string containing all signed certificate requests and certificates" do
- @ca.expects(:list).returns %w{host1 host2}
+ applier = @class.new(:list, :to => :signed)
- @applier = @class.new(:list, :to => :signed)
+ applier.expects(:puts).with(<<-OUTPUT.chomp)
++ host4 (fingerprint)
++ host5 (fingerprint)
++ host6 (fingerprint)
+ OUTPUT
- @applier.apply(@ca)
+ applier.apply(@ca)
+ end
+
+ it "should include subject alt names if they are on the certificate request" do
+ @csr.stubs(:subject_alt_names).returns ["DNS:foo", "DNS:bar"]
+
+ applier = @class.new(:list, :to => ['host1'])
+
+ applier.expects(:puts).with(<<-OUTPUT.chomp)
+ host1 (fingerprint) (alt names: DNS:foo, DNS:bar)
+ OUTPUT
+
+ applier.apply(@ca)
end
end
describe "and an array of names was provided" do
- it "should print a string of all named hosts that have a waiting request" do
- @ca.expects(:waiting?).returns %w{host1 host2}
- @ca.expects(:list).returns %w{host3 host4}
- @ca.stubs(:fingerprint).returns "fingerprint"
- @ca.stubs(:verify)
-
- @applier = @class.new(:list, :to => %w{host1 host2 host3 host4})
+ it "should print all named hosts" do
+ applier = @class.new(:list, :to => %w{host1 host2 host4 host5})
- @applier.expects(:puts).with "host1 (fingerprint)"
- @applier.expects(:puts).with "host2 (fingerprint)"
- @applier.expects(:puts).with "+ host3 (fingerprint)"
- @applier.expects(:puts).with "+ host4 (fingerprint)"
+ applier.expects(:puts).with(<<-OUTPUT.chomp)
+ host1 (fingerprint)
+ host2 (fingerprint)
++ host4 (fingerprint)
++ host5 (fingerprint)
+ OUTPUT
- @applier.apply(@ca)
+ applier.apply(@ca)
end
end
end
describe ":print" do
describe "and :all was provided" do
it "should print all certificates" do
@ca.expects(:list).returns %w{host1 host2}
@applier = @class.new(:print, :to => :all)
@ca.expects(:print).with("host1").returns "h1"
@applier.expects(:puts).with "h1"
@ca.expects(:print).with("host2").returns "h2"
@applier.expects(:puts).with "h2"
@applier.apply(@ca)
end
end
describe "and an array of names was provided" do
it "should print each named certificate if found" do
@applier = @class.new(:print, :to => %w{host1 host2})
@ca.expects(:print).with("host1").returns "h1"
@applier.expects(:puts).with "h1"
@ca.expects(:print).with("host2").returns "h2"
@applier.expects(:puts).with "h2"
@applier.apply(@ca)
end
it "should log any named but not found certificates" do
@applier = @class.new(:print, :to => %w{host1 host2})
@ca.expects(:print).with("host1").returns "h1"
@applier.expects(:puts).with "h1"
@ca.expects(:print).with("host2").returns nil
Puppet.expects(:err).with { |msg| msg.include?("host2") }
@applier.apply(@ca)
end
end
end
describe ":fingerprint" do
it "should fingerprint with the set digest algorithm" do
@applier = @class.new(:fingerprint, :to => %w{host1}, :digest => :digest)
@ca.expects(:fingerprint).with("host1", :digest).returns "fingerprint1"
@applier.expects(:puts).with "host1 fingerprint1"
@applier.apply(@ca)
end
describe "and :all was provided" do
it "should fingerprint all certificates (including waiting ones)" do
@ca.expects(:list).returns %w{host1}
@ca.expects(:waiting?).returns %w{host2}
@applier = @class.new(:fingerprint, :to => :all)
@ca.expects(:fingerprint).with("host1", :MD5).returns "fingerprint1"
@applier.expects(:puts).with "host1 fingerprint1"
@ca.expects(:fingerprint).with("host2", :MD5).returns "fingerprint2"
@applier.expects(:puts).with "host2 fingerprint2"
@applier.apply(@ca)
end
end
describe "and an array of names was provided" do
it "should print each named certificate if found" do
@applier = @class.new(:fingerprint, :to => %w{host1 host2})
@ca.expects(:fingerprint).with("host1", :MD5).returns "fingerprint1"
@applier.expects(:puts).with "host1 fingerprint1"
@ca.expects(:fingerprint).with("host2", :MD5).returns "fingerprint2"
@applier.expects(:puts).with "host2 fingerprint2"
@applier.apply(@ca)
end
end
end
end
end
diff --git a/spec/unit/ssl/certificate_authority_spec.rb b/spec/unit/ssl/certificate_authority_spec.rb
index 3c5780a43..222b72e5f 100755
--- a/spec/unit/ssl/certificate_authority_spec.rb
+++ b/spec/unit/ssl/certificate_authority_spec.rb
@@ -1,772 +1,882 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/ssl/certificate_authority'
describe Puppet::SSL::CertificateAuthority do
after do
Puppet::SSL::CertificateAuthority.instance_variable_set(:@singleton_instance, nil)
Puppet.settings.clearused
end
def stub_ca_host
@key = mock 'key'
@key.stubs(:content).returns "cakey"
@cacert = mock 'certificate'
@cacert.stubs(:content).returns "cacertificate"
@host = stub 'ssl_host', :key => @key, :certificate => @cacert, :name => Puppet::SSL::Host.ca_name
end
it "should have a class method for returning a singleton instance" do
Puppet::SSL::CertificateAuthority.should respond_to(:instance)
end
describe "when finding an existing instance" do
describe "and the host is a CA host and the run_mode is master" do
before do
Puppet[:ca] = true
Puppet.run_mode.stubs(:master?).returns true
@ca = mock('ca')
Puppet::SSL::CertificateAuthority.stubs(:new).returns @ca
end
it "should return an instance" do
Puppet::SSL::CertificateAuthority.instance.should equal(@ca)
end
it "should always return the same instance" do
Puppet::SSL::CertificateAuthority.instance.should equal(Puppet::SSL::CertificateAuthority.instance)
end
end
describe "and the host is not a CA host" do
it "should return nil" do
Puppet.settings.stubs(:value).with(:ca).returns false
Puppet.run_mode.stubs(:master?).returns true
ca = mock('ca')
Puppet::SSL::CertificateAuthority.expects(:new).never
Puppet::SSL::CertificateAuthority.instance.should be_nil
end
end
describe "and the run_mode is not master" do
it "should return nil" do
Puppet.settings.stubs(:value).with(:ca).returns true
Puppet.run_mode.stubs(:master?).returns false
ca = mock('ca')
Puppet::SSL::CertificateAuthority.expects(:new).never
Puppet::SSL::CertificateAuthority.instance.should be_nil
end
end
end
describe "when initializing" do
before do
Puppet.settings.stubs(:use)
Puppet.settings.stubs(:value).returns "ca_testing"
Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
end
it "should always set its name to the value of :certname" do
Puppet.settings.expects(:value).with(:certname).returns "ca_testing"
Puppet::SSL::CertificateAuthority.new.name.should == "ca_testing"
end
it "should create an SSL::Host instance whose name is the 'ca_name'" do
Puppet::SSL::Host.expects(:ca_name).returns "caname"
host = stub 'host'
Puppet::SSL::Host.expects(:new).with("caname").returns host
Puppet::SSL::CertificateAuthority.new
end
it "should use the :main, :ca, and :ssl settings sections" do
Puppet.settings.expects(:use).with(:main, :ssl, :ca)
Puppet::SSL::CertificateAuthority.new
end
it "should create an inventory instance" do
Puppet::SSL::Inventory.expects(:new).returns "inventory"
Puppet::SSL::CertificateAuthority.new.inventory.should == "inventory"
end
it "should make sure the CA is set up" do
Puppet::SSL::CertificateAuthority.any_instance.expects(:setup)
Puppet::SSL::CertificateAuthority.new
end
end
describe "when setting itself up" do
it "should generate the CA certificate if it does not have one" do
Puppet.settings.stubs :use
host = stub 'host'
Puppet::SSL::Host.stubs(:new).returns host
host.expects(:certificate).returns nil
Puppet::SSL::CertificateAuthority.any_instance.expects(:generate_ca_certificate)
Puppet::SSL::CertificateAuthority.new
end
end
describe "when retrieving the certificate revocation list" do
before do
Puppet.settings.stubs(:use)
Puppet.settings.stubs(:value).returns "ca_testing"
Puppet.settings.stubs(:value).with(:cacrl).returns "/my/crl"
cert = stub("certificate", :content => "real_cert")
key = stub("key", :content => "real_key")
@host = stub 'host', :certificate => cert, :name => "hostname", :key => key
Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
@ca = Puppet::SSL::CertificateAuthority.new
@ca.stubs(:host).returns @host
end
it "should return any found CRL instance" do
crl = mock 'crl'
Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns crl
@ca.crl.should equal(crl)
end
it "should create, generate, and save a new CRL instance of no CRL can be found" do
crl = Puppet::SSL::CertificateRevocationList.new("fakename")
Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns nil
Puppet::SSL::CertificateRevocationList.expects(:new).returns crl
crl.expects(:generate).with(@ca.host.certificate.content, @ca.host.key.content)
Puppet::SSL::CertificateRevocationList.indirection.expects(:save).with(crl)
@ca.crl.should equal(crl)
end
end
describe "when generating a self-signed CA certificate" do
before do
Puppet.settings.stubs(:use)
Puppet.settings.stubs(:value).returns "ca_testing"
Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
Puppet::SSL::CertificateAuthority.any_instance.stubs(:crl)
@ca = Puppet::SSL::CertificateAuthority.new
@host = stub 'host', :key => mock("key"), :name => "hostname", :certificate => mock('certificate')
Puppet::SSL::CertificateRequest.any_instance.stubs(:generate)
@ca.stubs(:host).returns @host
end
it "should create and store a password at :capass" do
Puppet.settings.expects(:value).with(:capass).returns "/path/to/pass"
FileTest.expects(:exist?).with("/path/to/pass").returns false
fh = mock 'filehandle'
Puppet.settings.expects(:write).with(:capass).yields fh
fh.expects(:print).with { |s| s.length > 18 }
@ca.stubs(:sign)
@ca.generate_ca_certificate
end
it "should generate a key if one does not exist" do
@ca.stubs :generate_password
@ca.stubs :sign
@ca.host.expects(:key).returns nil
@ca.host.expects(:generate_key)
@ca.generate_ca_certificate
end
it "should create and sign a self-signed cert using the CA name" do
request = mock 'request'
Puppet::SSL::CertificateRequest.expects(:new).with(@ca.host.name).returns request
request.expects(:generate).with(@ca.host.key)
+ request.stubs(:request_extensions => [])
- @ca.expects(:sign).with(@host.name, :ca, request)
+ @ca.expects(:sign).with(@host.name, false, request)
@ca.stubs :generate_password
@ca.generate_ca_certificate
end
it "should generate its CRL" do
@ca.stubs :generate_password
@ca.stubs :sign
@ca.host.expects(:key).returns nil
@ca.host.expects(:generate_key)
@ca.expects(:crl)
@ca.generate_ca_certificate
end
end
describe "when signing" do
before do
Puppet.settings.stubs(:use)
Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
stub_ca_host
Puppet::SSL::Host.expects(:new).with(Puppet::SSL::Host.ca_name).returns @host
@ca = Puppet::SSL::CertificateAuthority.new
@name = "myhost"
@real_cert = stub 'realcert', :sign => nil
@cert = Puppet::SSL::Certificate.new(@name)
@cert.content = @real_cert
Puppet::SSL::Certificate.stubs(:new).returns @cert
@cert.stubs(:content=)
Puppet::SSL::Certificate.indirection.stubs(:save)
# Stub out the factory
- @factory = stub 'factory', :result => "my real cert"
- Puppet::SSL::CertificateFactory.stubs(:new).returns @factory
+ Puppet::SSL::CertificateFactory.stubs(:build).returns "my real cert"
- @request = stub 'request', :content => "myrequest", :name => @name
+ @request_content = stub "request content stub", :subject => @name
+ @request = stub 'request', :name => @name, :request_extensions => [], :subject_alt_names => [], :content => @request_content
# And the inventory
@inventory = stub 'inventory', :add => nil
@ca.stubs(:inventory).returns @inventory
Puppet::SSL::CertificateRequest.indirection.stubs(:destroy)
end
describe "and calculating the next certificate serial number" do
before do
@path = "/path/to/serial"
Puppet.settings.stubs(:value).with(:serial).returns @path
@filehandle = stub 'filehandle', :<< => @filehandle
Puppet.settings.stubs(:readwritelock).with(:serial).yields @filehandle
end
it "should default to 0x1 for the first serial number" do
@ca.next_serial.should == 0x1
end
it "should return the current content of the serial file" do
FileTest.stubs(:exist?).with(@path).returns true
File.expects(:read).with(@path).returns "0002"
@ca.next_serial.should == 2
end
it "should write the next serial number to the serial file as hex" do
@filehandle.expects(:<<).with("0002")
@ca.next_serial
end
it "should lock the serial file while writing" do
Puppet.settings.expects(:readwritelock).with(:serial)
@ca.next_serial
end
end
describe "its own certificate" do
before do
@serial = 10
@ca.stubs(:next_serial).returns @serial
end
it "should not look up a certificate request for the host" do
Puppet::SSL::CertificateRequest.indirection.expects(:find).never
- @ca.sign(@name, :ca, @request)
+ @ca.sign(@name, true, @request)
end
it "should use a certificate type of :ca" do
- Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
args[0] == :ca
- end.returns @factory
+ end.returns "my real cert"
@ca.sign(@name, :ca, @request)
end
it "should pass the provided CSR as the CSR" do
- Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
- args[1] == "myrequest"
- end.returns @factory
+ Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
+ args[1] == @request
+ end.returns "my real cert"
@ca.sign(@name, :ca, @request)
end
it "should use the provided CSR's content as the issuer" do
- Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
- args[2] == "myrequest"
- end.returns @factory
+ Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
+ args[2].subject == "myhost"
+ end.returns "my real cert"
@ca.sign(@name, :ca, @request)
end
it "should pass the next serial as the serial number" do
- Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
args[3] == @serial
- end.returns @factory
+ end.returns "my real cert"
@ca.sign(@name, :ca, @request)
end
+ it "should sign the certificate request even if it contains alt names" do
+ @request.stubs(:subject_alt_names).returns %w[DNS:foo DNS:bar DNS:baz]
+
+ expect do
+ @ca.sign(@name, false, @request)
+ end.should_not raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError)
+ end
+
it "should save the resulting certificate" do
Puppet::SSL::Certificate.indirection.expects(:save).with(@cert)
@ca.sign(@name, :ca, @request)
end
end
describe "another host's certificate" do
before do
@serial = 10
@ca.stubs(:next_serial).returns @serial
Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
Puppet::SSL::CertificateRequest.indirection.stubs :save
end
it "should use a certificate type of :server" do
- Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
args[0] == :server
- end.returns @factory
+ end.returns "my real cert"
@ca.sign(@name)
end
it "should use look up a CSR for the host in the :ca_file terminus" do
Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns @request
@ca.sign(@name)
end
it "should fail if no CSR can be found for the host" do
Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns nil
lambda { @ca.sign(@name) }.should raise_error(ArgumentError)
end
+ it "should fail if an unknown request extension is present" do
+ @request.stubs :request_extensions => [{ "oid" => "bananas",
+ "value" => "delicious" }]
+ expect { @ca.sign(@name) }.
+ should raise_error(/CSR has request extensions that are not permitted/)
+ end
+
+ it "should fail if the CSR contains alt names and they are not expected" do
+ @request.stubs(:subject_alt_names).returns %w[DNS:foo DNS:bar DNS:baz]
+
+ expect do
+ @ca.sign(@name, false)
+ end.to raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError, /CSR '#{@name}' contains subject alternative names \(.*?\), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{@name}` to sign this request./)
+ end
+
+ it "should not fail if the CSR does not contain alt names and they are expected" do
+ @request.stubs(:subject_alt_names).returns []
+ expect { @ca.sign(@name, true) }.should_not raise_error
+ end
+
+ it "should reject alt names by default" do
+ @request.stubs(:subject_alt_names).returns %w[DNS:foo DNS:bar DNS:baz]
+
+ expect do
+ @ca.sign(@name)
+ end.to raise_error(Puppet::SSL::CertificateAuthority::CertificateSigningError, /CSR '#{@name}' contains subject alternative names \(.*?\), which are disallowed. Use `puppet cert --allow-dns-alt-names sign #{@name}` to sign this request./)
+ end
+
it "should use the CA certificate as the issuer" do
- Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
args[2] == @cacert.content
- end.returns @factory
+ end.returns "my real cert"
@ca.sign(@name)
end
it "should pass the next serial as the serial number" do
- Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
+ Puppet::SSL::CertificateFactory.expects(:build).with do |*args|
args[3] == @serial
- end.returns @factory
+ end.returns "my real cert"
@ca.sign(@name)
end
it "should sign the resulting certificate using its real key and a digest" do
digest = mock 'digest'
OpenSSL::Digest::SHA1.expects(:new).returns digest
key = stub 'key', :content => "real_key"
@ca.host.stubs(:key).returns key
@cert.content.expects(:sign).with("real_key", digest)
@ca.sign(@name)
end
it "should save the resulting certificate" do
Puppet::SSL::Certificate.indirection.stubs(:save).with(@cert)
@ca.sign(@name)
end
it "should remove the host's certificate request" do
Puppet::SSL::CertificateRequest.indirection.expects(:destroy).with(@name)
@ca.sign(@name)
end
+
+ it "should check the internal signing policies" do
+ @ca.expects(:check_internal_signing_policies).returns true
+ @ca.sign(@name)
+ end
+ end
+
+ context "#check_internal_signing_policies" do
+ before do
+ @serial = 10
+ @ca.stubs(:next_serial).returns @serial
+
+ Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
+ @cert.stubs :save
+ end
+
+ it "should reject a critical extension that isn't on the whitelist" do
+ @request.stubs(:request_extensions).returns [{ "oid" => "banana",
+ "value" => "yumm",
+ "critical" => true }]
+ expect { @ca.sign(@name) }.to raise_error(
+ Puppet::SSL::CertificateAuthority::CertificateSigningError,
+ /request extensions that are not permitted/
+ )
+ end
+
+ it "should reject a non-critical extension that isn't on the whitelist" do
+ @request.stubs(:request_extensions).returns [{ "oid" => "peach",
+ "value" => "meh",
+ "critical" => false }]
+ expect { @ca.sign(@name) }.to raise_error(
+ Puppet::SSL::CertificateAuthority::CertificateSigningError,
+ /request extensions that are not permitted/
+ )
+ end
+
+ it "should reject non-whitelist extensions even if a valid extension is present" do
+ @request.stubs(:request_extensions).returns [{ "oid" => "peach",
+ "value" => "meh",
+ "critical" => false },
+ { "oid" => "subjectAltName",
+ "value" => "DNS:foo",
+ "critical" => true }]
+ expect { @ca.sign(@name) }.to raise_error(
+ Puppet::SSL::CertificateAuthority::CertificateSigningError,
+ /request extensions that are not permitted/
+ )
+ end
+
+ it "should reject a subjectAltName for a non-DNS value" do
+ @request.stubs(:subject_alt_names).returns ['DNS:foo', 'email:bar@example.com']
+ expect { @ca.sign(@name, true) }.to raise_error(
+ Puppet::SSL::CertificateAuthority::CertificateSigningError,
+ /subjectAltName outside the DNS label space/
+ )
+ end
+
+ it "should reject a wildcard subject" do
+ @request.content.stubs(:subject).
+ returns(OpenSSL::X509::Name.new([["CN", "*.local"]]))
+
+ expect { @ca.sign(@name) }.to raise_error(
+ Puppet::SSL::CertificateAuthority::CertificateSigningError,
+ /subject contains a wildcard/
+ )
+ end
+
+ it "should reject a wildcard subjectAltName" do
+ @request.stubs(:subject_alt_names).returns ['DNS:foo', 'DNS:*.bar']
+ expect { @ca.sign(@name, true) }.to raise_error(
+ Puppet::SSL::CertificateAuthority::CertificateSigningError,
+ /subjectAltName contains a wildcard/
+ )
+ end
end
it "should create a certificate instance with the content set to the newly signed x509 certificate" do
@serial = 10
@ca.stubs(:next_serial).returns @serial
Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
Puppet::SSL::Certificate.indirection.stubs :save
Puppet::SSL::Certificate.expects(:new).with(@name).returns @cert
@ca.sign(@name)
end
it "should return the certificate instance" do
@ca.stubs(:next_serial).returns @serial
Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
Puppet::SSL::Certificate.indirection.stubs :save
@ca.sign(@name).should equal(@cert)
end
it "should add the certificate to its inventory" do
@ca.stubs(:next_serial).returns @serial
@inventory.expects(:add).with(@cert)
Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
Puppet::SSL::Certificate.indirection.stubs :save
@ca.sign(@name)
end
it "should have a method for triggering autosigning of available CSRs" do
@ca.should respond_to(:autosign)
end
describe "when autosigning certificates" do
it "should do nothing if autosign is disabled" do
Puppet.settings.expects(:value).with(:autosign).returns 'false'
Puppet::SSL::CertificateRequest.indirection.expects(:search).never
@ca.autosign
end
it "should do nothing if no autosign.conf exists" do
Puppet.settings.expects(:value).with(:autosign).returns '/auto/sign'
FileTest.expects(:exist?).with("/auto/sign").returns false
Puppet::SSL::CertificateRequest.indirection.expects(:search).never
@ca.autosign
end
describe "and autosign is enabled and the autosign.conf file exists" do
before do
Puppet.settings.stubs(:value).with(:autosign).returns '/auto/sign'
FileTest.stubs(:exist?).with("/auto/sign").returns true
File.stubs(:readlines).with("/auto/sign").returns ["one\n", "two\n"]
Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns []
@store = stub 'store', :allow => nil
Puppet::Network::AuthStore.stubs(:new).returns @store
end
describe "when creating the AuthStore instance to verify autosigning" do
it "should create an AuthStore with each line in the configuration file allowed to be autosigned" do
Puppet::Network::AuthStore.expects(:new).returns @store
@store.expects(:allow).with("one")
@store.expects(:allow).with("two")
@ca.autosign
end
it "should reparse the autosign configuration on each call" do
Puppet::Network::AuthStore.expects(:new).times(2).returns @store
@ca.autosign
@ca.autosign
end
it "should ignore comments" do
File.stubs(:readlines).with("/auto/sign").returns ["one\n", "#two\n"]
@store.expects(:allow).with("one")
@ca.autosign
end
it "should ignore blank lines" do
File.stubs(:readlines).with("/auto/sign").returns ["one\n", "\n"]
@store.expects(:allow).with("one")
@ca.autosign
end
end
it "should sign all CSRs whose hostname matches the autosign configuration" do
csr1 = mock 'csr1'
csr2 = mock 'csr2'
Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2]
end
it "should not sign CSRs whose hostname does not match the autosign configuration" do
csr1 = mock 'csr1'
csr2 = mock 'csr2'
Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2]
end
end
end
end
describe "when managing certificate clients" do
before do
Puppet.settings.stubs(:use)
Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
stub_ca_host
Puppet::SSL::Host.expects(:new).returns @host
Puppet::SSL::CertificateAuthority.any_instance.stubs(:host).returns @host
@cacert = mock 'certificate'
@cacert.stubs(:content).returns "cacertificate"
@ca = Puppet::SSL::CertificateAuthority.new
end
it "should have a method for acting on the SSL files" do
@ca.should respond_to(:apply)
end
describe "when applying a method to a set of hosts" do
it "should fail if no subjects have been specified" do
lambda { @ca.apply(:generate) }.should raise_error(ArgumentError)
end
it "should create an Interface instance with the specified method and the options" do
Puppet::SSL::CertificateAuthority::Interface.expects(:new).with(:generate, :to => :host).returns(stub('applier', :apply => nil))
@ca.apply(:generate, :to => :host)
end
it "should apply the Interface with itself as the argument" do
applier = stub('applier')
applier.expects(:apply).with(@ca)
Puppet::SSL::CertificateAuthority::Interface.expects(:new).returns applier
@ca.apply(:generate, :to => :ca_testing)
end
end
it "should be able to list waiting certificate requests" do
req1 = stub 'req1', :name => "one"
req2 = stub 'req2', :name => "two"
Puppet::SSL::CertificateRequest.indirection.expects(:search).with("*").returns [req1, req2]
@ca.waiting?.should == %w{one two}
end
it "should delegate removing hosts to the Host class" do
Puppet::SSL::Host.expects(:destroy).with("myhost")
@ca.destroy("myhost")
end
it "should be able to verify certificates" do
@ca.should respond_to(:verify)
end
it "should list certificates as the sorted list of all existing signed certificates" do
cert1 = stub 'cert1', :name => "cert1"
cert2 = stub 'cert2', :name => "cert2"
Puppet::SSL::Certificate.indirection.expects(:search).with("*").returns [cert1, cert2]
@ca.list.should == %w{cert1 cert2}
end
describe "and printing certificates" do
it "should return nil if the certificate cannot be found" do
Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil
@ca.print("myhost").should be_nil
end
it "should print certificates by calling :to_text on the host's certificate" do
cert1 = stub 'cert1', :name => "cert1", :to_text => "mytext"
Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns cert1
@ca.print("myhost").should == "mytext"
end
end
describe "and fingerprinting certificates" do
before :each do
@cert = stub 'cert', :name => "cert", :fingerprint => "DIGEST"
Puppet::SSL::Certificate.indirection.stubs(:find).with("myhost").returns @cert
Puppet::SSL::CertificateRequest.indirection.stubs(:find).with("myhost")
end
it "should raise an error if the certificate or CSR cannot be found" do
Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil
Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns nil
lambda { @ca.fingerprint("myhost") }.should raise_error
end
it "should try to find a CSR if no certificate can be found" do
Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil
Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns @cert
@cert.expects(:fingerprint)
@ca.fingerprint("myhost")
end
it "should delegate to the certificate fingerprinting" do
@cert.expects(:fingerprint)
@ca.fingerprint("myhost")
end
it "should propagate the digest algorithm to the certificate fingerprinting system" do
@cert.expects(:fingerprint).with(:digest)
@ca.fingerprint("myhost", :digest)
end
end
describe "and verifying certificates" do
before do
@store = stub 'store', :verify => true, :add_file => nil, :purpose= => nil, :add_crl => true, :flags= => nil
OpenSSL::X509::Store.stubs(:new).returns @store
Puppet.settings.stubs(:value).returns "crtstuff"
@cert = stub 'cert', :content => "mycert"
Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert
@crl = stub('crl', :content => "mycrl")
@ca.stubs(:crl).returns @crl
end
it "should fail if the host's certificate cannot be found" do
Puppet::SSL::Certificate.indirection.expects(:find).with("me").returns(nil)
lambda { @ca.verify("me") }.should raise_error(ArgumentError)
end
it "should create an SSL Store to verify" do
OpenSSL::X509::Store.expects(:new).returns @store
@ca.verify("me")
end
it "should add the CA Certificate to the store" do
Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
@store.expects(:add_file).with "/ca/cert"
@ca.verify("me")
end
it "should add the CRL to the store if the crl is enabled" do
@store.expects(:add_crl).with "mycrl"
@ca.verify("me")
end
it "should set the store purpose to OpenSSL::X509::PURPOSE_SSL_CLIENT" do
Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
@store.expects(:add_file).with "/ca/cert"
@ca.verify("me")
end
it "should set the store flags to check the crl" do
@store.expects(:flags=).with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK
@ca.verify("me")
end
it "should use the store to verify the certificate" do
@cert.expects(:content).returns "mycert"
@store.expects(:verify).with("mycert").returns true
@ca.verify("me")
end
it "should fail if the verification returns false" do
@cert.expects(:content).returns "mycert"
@store.expects(:verify).with("mycert").returns false
lambda { @ca.verify("me") }.should raise_error
end
end
describe "and revoking certificates" do
before do
@crl = mock 'crl'
@ca.stubs(:crl).returns @crl
@ca.stubs(:next_serial).returns 10
@real_cert = stub 'real_cert', :serial => 15
@cert = stub 'cert', :content => @real_cert
Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert
end
it "should fail if the certificate revocation list is disabled" do
@ca.stubs(:crl).returns false
lambda { @ca.revoke('ca_testing') }.should raise_error(ArgumentError)
end
it "should delegate the revocation to its CRL" do
@ca.crl.expects(:revoke)
@ca.revoke('host')
end
it "should get the serial number from the local certificate if it exists" do
@ca.crl.expects(:revoke).with { |serial, key| serial == 15 }
Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns @cert
@ca.revoke('host')
end
it "should get the serial number from inventory if no local certificate exists" do
real_cert = stub 'real_cert', :serial => 15
cert = stub 'cert', :content => real_cert
Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns nil
@ca.inventory.expects(:serial).with("host").returns 16
@ca.crl.expects(:revoke).with { |serial, key| serial == 16 }
@ca.revoke('host')
end
end
it "should be able to generate a complete new SSL host" do
@ca.should respond_to(:generate)
end
describe "and generating certificates" do
before do
@host = stub 'host', :generate_certificate_request => nil
Puppet::SSL::Host.stubs(:new).returns @host
Puppet::SSL::Certificate.indirection.stubs(:find).returns nil
@ca.stubs(:sign)
end
it "should fail if a certificate already exists for the host" do
Puppet::SSL::Certificate.indirection.expects(:find).with("him").returns "something"
lambda { @ca.generate("him") }.should raise_error(ArgumentError)
end
it "should create a new Host instance with the correct name" do
Puppet::SSL::Host.expects(:new).with("him").returns @host
@ca.generate("him")
end
it "should use the Host to generate the certificate request" do
@host.expects :generate_certificate_request
@ca.generate("him")
end
it "should sign the generated request" do
- @ca.expects(:sign).with("him")
-
+ @ca.expects(:sign).with("him", false)
@ca.generate("him")
end
end
end
end
diff --git a/spec/unit/ssl/certificate_factory_spec.rb b/spec/unit/ssl/certificate_factory_spec.rb
index f34dafe43..fc1b3a740 100755
--- a/spec/unit/ssl/certificate_factory_spec.rb
+++ b/spec/unit/ssl/certificate_factory_spec.rb
@@ -1,106 +1,126 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/ssl/certificate_factory'
describe Puppet::SSL::CertificateFactory do
- before do
- @cert_type = mock 'cert_type'
- @name = mock 'name'
- @csr = stub 'csr', :subject => @name
- @issuer = mock 'issuer'
- @serial = mock 'serial'
-
- @factory = Puppet::SSL::CertificateFactory.new(@cert_type, @csr, @issuer, @serial)
+ let :serial do OpenSSL::BN.new('12') end
+ let :name do "example.local" end
+ let :x509_name do OpenSSL::X509::Name.new([['CN', name]]) end
+ let :key do Puppet::SSL::Key.new(name).generate end
+ let :csr do
+ csr = Puppet::SSL::CertificateRequest.new(name)
+ csr.generate(key)
+ csr
end
-
- describe "when initializing" do
- it "should set its :cert_type to its first argument" do
- @factory.cert_type.should equal(@cert_type)
- end
-
- it "should set its :csr to its second argument" do
- @factory.csr.should equal(@csr)
- end
-
- it "should set its :issuer to its third argument" do
- @factory.issuer.should equal(@issuer)
- end
-
- it "should set its :serial to its fourth argument" do
- @factory.serial.should equal(@serial)
- end
-
- it "should set its name to the subject of the csr" do
- @factory.name.should equal(@name)
- end
+ let :issuer do
+ cert = OpenSSL::X509::Certificate.new
+ cert.subject = OpenSSL::X509::Name.new([["CN", 'issuer.local']])
+ cert
end
describe "when generating the certificate" do
- before do
- @cert = mock 'cert'
-
- @cert.stub_everything
-
- @factory.stubs :build_extensions
-
- @factory.stubs :set_ttl
-
- @issuer_name = mock 'issuer_name'
- @issuer.stubs(:subject).returns @issuer_name
-
- @public_key = mock 'public_key'
- @csr.stubs(:public_key).returns @public_key
-
- OpenSSL::X509::Certificate.stubs(:new).returns @cert
- end
-
it "should return a new X509 certificate" do
- OpenSSL::X509::Certificate.expects(:new).returns @cert
- @factory.result.should equal(@cert)
+ subject.build(:server, csr, issuer, serial).should_not ==
+ subject.build(:server, csr, issuer, serial)
end
it "should set the certificate's version to 2" do
- @cert.expects(:version=).with 2
- @factory.result
+ subject.build(:server, csr, issuer, serial).version.should == 2
end
it "should set the certificate's subject to the CSR's subject" do
- @cert.expects(:subject=).with @name
- @factory.result
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.subject.should eql x509_name
end
it "should set the certificate's issuer to the Issuer's subject" do
- @cert.expects(:issuer=).with @issuer_name
- @factory.result
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.issuer.should eql issuer.subject
end
it "should set the certificate's public key to the CSR's public key" do
- @cert.expects(:public_key=).with @public_key
- @factory.result
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.public_key.should be_public
+ cert.public_key.to_s.should == csr.content.public_key.to_s
end
it "should set the certificate's serial number to the provided serial number" do
- @cert.expects(:serial=).with @serial
- @factory.result
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.serial.should == serial
+ end
+
+ it "should have 24 hours grace on the start of the cert" do
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.not_before.should be_within(1).of(Time.now - 24*60*60)
+ end
+
+ it "should set the default TTL of the certificate" do
+ ttl = Puppet::SSL::CertificateFactory.ttl
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.not_after.should be_within(1).of(Time.now + ttl)
+ end
+
+ it "should respect a custom TTL for the CA" do
+ Puppet[:ca_ttl] = 12
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.not_after.should be_within(1).of(Time.now + 12)
end
it "should build extensions for the certificate" do
- @factory.expects(:build_extensions)
- @factory.result
+ cert = subject.build(:server, csr, issuer, serial)
+ cert.extensions.map {|x| x.to_h }.find {|x| x["oid"] == "nsComment" }.should ==
+ { "oid" => "nsComment",
+ "value" => "Puppet Ruby/OpenSSL Internal Certificate",
+ "critical" => false }
end
- it "should set the ttl of the certificate" do
- @factory.expects(:set_ttl)
- @factory.result
+ # See #2848 for why we are doing this: we need to make sure that
+ # subjectAltName is set if the CSR has it, but *not* if it is set when the
+ # certificate is built!
+ it "should not add subjectAltNames from dns_alt_names" do
+ Puppet[:dns_alt_names] = 'one, two'
+ # Verify the CSR still has no extReq, just in case...
+ csr.request_extensions.should == []
+ cert = subject.build(:server, csr, issuer, serial)
+
+ cert.extensions.find {|x| x.oid == 'subjectAltName' }.should be_nil
end
- end
- describe "when building extensions" do
- it "should have tests"
- end
+ it "should add subjectAltName when the CSR requests them" do
+ Puppet[:dns_alt_names] = ''
+
+ expect = %w{one two} + [name]
+
+ csr = Puppet::SSL::CertificateRequest.new(name)
+ csr.generate(key, :dns_alt_names => expect.join(', '))
- describe "when setting the ttl" do
- it "should have tests"
+ csr.request_extensions.should_not be_nil
+ csr.subject_alt_names.should =~ expect.map{|x| "DNS:#{x}"}
+
+ cert = subject.build(:server, csr, issuer, serial)
+ san = cert.extensions.find {|x| x.oid == 'subjectAltName' }
+ san.should_not be_nil
+ expect.each do |name|
+ san.value.should =~ /DNS:#{name}\b/i
+ end
+ end
+
+ # Can't check the CA here, since that requires way more infrastructure
+ # that I want to build up at this time. We can verify the critical
+ # values, though, which are non-CA certs. --daniel 2011-10-11
+ { :ca => 'CA:TRUE',
+ :terminalsubca => ['CA:TRUE', 'pathlen:0'],
+ :server => 'CA:FALSE',
+ :ocsp => 'CA:FALSE',
+ :client => 'CA:FALSE',
+ }.each do |name, value|
+ it "should set basicConstraints for #{name} #{value.inspect}" do
+ cert = subject.build(name, csr, issuer, serial)
+ bc = cert.extensions.find {|x| x.oid == 'basicConstraints' }
+ bc.should be
+ bc.value.split(/\s*,\s*/).should =~ Array(value)
+ end
+ end
end
end
diff --git a/spec/unit/ssl/certificate_request_spec.rb b/spec/unit/ssl/certificate_request_spec.rb
index e45f0130b..9a27397d4 100755
--- a/spec/unit/ssl/certificate_request_spec.rb
+++ b/spec/unit/ssl/certificate_request_spec.rb
@@ -1,216 +1,277 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/ssl/certificate_request'
require 'puppet/ssl/key'
describe Puppet::SSL::CertificateRequest do
before do
@class = Puppet::SSL::CertificateRequest
end
it "should be extended with the Indirector module" do
@class.singleton_class.should be_include(Puppet::Indirector)
end
it "should indirect certificate_request" do
@class.indirection.name.should == :certificate_request
end
it "should use any provided name as its name" do
@class.new("myname").name.should == "myname"
end
it "should only support the text format" do
@class.supported_formats.should == [:s]
end
describe "when converting from a string" do
it "should create a CSR instance with its name set to the CSR subject and its content set to the extracted CSR" do
csr = stub 'csr', :subject => "/CN=Foo.madstop.com"
OpenSSL::X509::Request.expects(:new).with("my csr").returns(csr)
mycsr = stub 'sslcsr'
mycsr.expects(:content=).with(csr)
@class.expects(:new).with("foo.madstop.com").returns mycsr
@class.from_s("my csr")
end
end
describe "when managing instances" do
before do
@request = @class.new("myname")
end
it "should have a name attribute" do
@request.name.should == "myname"
end
it "should downcase its name" do
@class.new("MyName").name.should == "myname"
end
it "should have a content attribute" do
@request.should respond_to(:content)
end
it "should be able to read requests from disk" do
path = "/my/path"
File.expects(:read).with(path).returns("my request")
request = mock 'request'
OpenSSL::X509::Request.expects(:new).with("my request").returns(request)
@request.read(path).should equal(request)
@request.content.should equal(request)
end
it "should return an empty string when converted to a string with no request" do
@request.to_s.should == ""
end
it "should convert the request to pem format when converted to a string" do
request = mock 'request', :to_pem => "pem"
@request.content = request
@request.to_s.should == "pem"
end
it "should have a :to_text method that it delegates to the actual key" do
real_request = mock 'request'
real_request.expects(:to_text).returns "requesttext"
@request.content = real_request
@request.to_text.should == "requesttext"
end
end
describe "when generating" do
before do
@instance = @class.new("myname")
key = Puppet::SSL::Key.new("myname")
@key = key.generate
@request = OpenSSL::X509::Request.new
OpenSSL::X509::Request.expects(:new).returns(@request)
@request.stubs(:verify).returns(true)
end
it "should use the content of the provided key if the key is a Puppet::SSL::Key instance" do
key = Puppet::SSL::Key.new("test")
key.expects(:content).returns @key
@request.expects(:sign).with{ |key, digest| key == @key }
@instance.generate(key)
end
it "should log that it is creating a new certificate request" do
Puppet.expects(:info).twice
@instance.generate(@key)
end
it "should set the subject to [CN, name]" do
subject = mock 'subject'
OpenSSL::X509::Name.expects(:new).with([["CN", @instance.name]]).returns(subject)
@request.expects(:subject=).with(subject)
@instance.generate(@key)
end
it "should set the CN to the CSR name when the CSR is not for a CA" do
subject = mock 'subject'
OpenSSL::X509::Name.expects(:new).with { |subject| subject[0][1] == @instance.name }.returns(subject)
@request.expects(:subject=).with(subject)
@instance.generate(@key)
end
it "should set the CN to the :ca_name setting when the CSR is for a CA" do
subject = mock 'subject'
- Puppet.settings.expects(:value).with(:ca_name).returns "mycertname"
+ Puppet[:ca_name] = "mycertname"
OpenSSL::X509::Name.expects(:new).with { |subject| subject[0][1] == "mycertname" }.returns(subject)
@request.expects(:subject=).with(subject)
Puppet::SSL::CertificateRequest.new(Puppet::SSL::CA_NAME).generate(@key)
end
it "should set the version to 0" do
@request.expects(:version=).with(0)
@instance.generate(@key)
end
it "should set the public key to the provided key's public key" do
# Yay, the private key extracts a new key each time.
pubkey = @key.public_key
@key.stubs(:public_key).returns pubkey
@request.expects(:public_key=).with(@key.public_key)
@instance.generate(@key)
end
+ context "without subjectAltName / dns_alt_names" do
+ before :each do
+ Puppet[:dns_alt_names] = ""
+ end
+
+ ["extreq", "msExtReq"].each do |name|
+ it "should not add any #{name} attribute" do
+ @request.expects(:add_attribute).never
+ @request.expects(:attributes=).never
+ @instance.generate(@key)
+ end
+
+ it "should return no subjectAltNames" do
+ @instance.generate(@key)
+ @instance.subject_alt_names.should be_empty
+ end
+ end
+ end
+
+ context "with dns_alt_names" do
+ before :each do
+ Puppet[:dns_alt_names] = "one, two, three"
+ end
+
+ ["extreq", "msExtReq"].each do |name|
+ it "should not add any #{name} attribute" do
+ @request.expects(:add_attribute).never
+ @request.expects(:attributes=).never
+ @instance.generate(@key)
+ end
+
+ it "should return no subjectAltNames" do
+ @instance.generate(@key)
+ @instance.subject_alt_names.should be_empty
+ end
+ end
+ end
+
+ context "with subjectAltName to generate request" do
+ before :each do
+ Puppet[:dns_alt_names] = ""
+ end
+
+ it "should add an extreq attribute" do
+ @request.expects(:add_attribute).with do |arg|
+ arg.value.value.all? do |x|
+ x.value.all? do |y|
+ y.value[0].value == "subjectAltName"
+ end
+ end
+ end
+
+ @instance.generate(@key, :dns_alt_names => 'one, two')
+ end
+
+ it "should return the subjectAltName values" do
+ @instance.generate(@key, :dns_alt_names => 'one,two')
+ @instance.subject_alt_names.should =~ ["DNS:myname", "DNS:one", "DNS:two"]
+ end
+ end
+
it "should sign the csr with the provided key and a digest" do
digest = mock 'digest'
OpenSSL::Digest::MD5.expects(:new).returns(digest)
@request.expects(:sign).with(@key, digest)
@instance.generate(@key)
end
it "should verify the generated request using the public key" do
# Stupid keys don't have a competent == method.
@request.expects(:verify).with { |public_key| public_key.to_s == @key.public_key.to_s }.returns true
@instance.generate(@key)
end
it "should fail if verification fails" do
@request.expects(:verify).returns false
lambda { @instance.generate(@key) }.should raise_error(Puppet::Error)
end
it "should fingerprint the request" do
@instance.expects(:fingerprint)
@instance.generate(@key)
end
it "should display the fingerprint" do
Puppet.stubs(:info)
@instance.stubs(:fingerprint).returns("FINGERPRINT")
Puppet.expects(:info).with { |s| s =~ /FINGERPRINT/ }
@instance.generate(@key)
end
it "should return the generated request" do
@instance.generate(@key).should equal(@request)
end
it "should set its content to the generated request" do
@instance.generate(@key)
@instance.content.should equal(@request)
end
end
describe "when a CSR is saved" do
describe "and a CA is available" do
it "should save the CSR and trigger autosigning" do
ca = mock 'ca', :autosign
Puppet::SSL::CertificateAuthority.expects(:instance).returns ca
csr = Puppet::SSL::CertificateRequest.new("me")
terminus = mock 'terminus'
Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus)
terminus.expects(:save).with { |request| request.instance == csr && request.key == "me" }
Puppet::SSL::CertificateRequest.indirection.save(csr)
end
end
describe "and a CA is not available" do
it "should save the CSR" do
Puppet::SSL::CertificateAuthority.expects(:instance).returns nil
csr = Puppet::SSL::CertificateRequest.new("me")
terminus = mock 'terminus'
Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus)
terminus.expects(:save).with { |request| request.instance == csr && request.key == "me" }
Puppet::SSL::CertificateRequest.indirection.save(csr)
end
end
end
end
diff --git a/spec/unit/ssl/certificate_spec.rb b/spec/unit/ssl/certificate_spec.rb
index de5cedf59..1d0ddb934 100755
--- a/spec/unit/ssl/certificate_spec.rb
+++ b/spec/unit/ssl/certificate_spec.rb
@@ -1,148 +1,154 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/ssl/certificate'
describe Puppet::SSL::Certificate do
before do
@class = Puppet::SSL::Certificate
end
after do
@class.instance_variable_set("@ca_location", nil)
end
it "should be extended with the Indirector module" do
@class.singleton_class.should be_include(Puppet::Indirector)
end
it "should indirect certificate" do
@class.indirection.name.should == :certificate
end
it "should only support the text format" do
@class.supported_formats.should == [:s]
end
describe "when converting from a string" do
it "should create a certificate instance with its name set to the certificate subject and its content set to the extracted certificate" do
cert = stub 'certificate', :subject => "/CN=Foo.madstop.com"
OpenSSL::X509::Certificate.expects(:new).with("my certificate").returns(cert)
mycert = stub 'sslcert'
mycert.expects(:content=).with(cert)
@class.expects(:new).with("foo.madstop.com").returns mycert
@class.from_s("my certificate")
end
it "should create multiple certificate instances when asked" do
cert1 = stub 'cert1'
@class.expects(:from_s).with("cert1").returns cert1
cert2 = stub 'cert2'
@class.expects(:from_s).with("cert2").returns cert2
@class.from_multiple_s("cert1\n---\ncert2").should == [cert1, cert2]
end
end
describe "when converting to a string" do
before do
@certificate = @class.new("myname")
end
it "should return an empty string when it has no certificate" do
@certificate.to_s.should == ""
end
it "should convert the certificate to pem format" do
certificate = mock 'certificate', :to_pem => "pem"
@certificate.content = certificate
@certificate.to_s.should == "pem"
end
it "should be able to convert multiple instances to a string" do
cert2 = @class.new("foo")
@certificate.expects(:to_s).returns "cert1"
cert2.expects(:to_s).returns "cert2"
@class.to_multiple_s([@certificate, cert2]).should == "cert1\n---\ncert2"
end
end
describe "when managing instances" do
before do
@certificate = @class.new("myname")
end
it "should have a name attribute" do
@certificate.name.should == "myname"
end
it "should convert its name to a string and downcase it" do
@class.new(:MyName).name.should == "myname"
end
it "should have a content attribute" do
@certificate.should respond_to(:content)
end
- describe "#alternate_names" do
- before do
- Puppet[:certdnsnames] = 'foo:bar:baz'
- @csr = OpenSSL::X509::Request.new
- @csr.subject = OpenSSL::X509::Name.new([['CN', 'quux']])
- @csr.public_key = OpenSSL::PKey::RSA.generate(Puppet[:keylength]).public_key
- end
-
+ describe "#subject_alt_names" do
it "should list all alternate names when the extension is present" do
- cert = Puppet::SSL::CertificateFactory.new('server', @csr, @csr, 14).result
+ key = Puppet::SSL::Key.new('quux')
+ key.generate
- @certificate = @class.from_s(cert.to_pem)
+ csr = Puppet::SSL::CertificateRequest.new('quux')
+ csr.generate(key, :dns_alt_names => 'foo, bar,baz')
- @certificate.alternate_names.should =~ ['foo', 'bar', 'baz', 'quux']
+ raw_csr = csr.content
+
+ cert = Puppet::SSL::CertificateFactory.build('server', csr, raw_csr, 14)
+ certificate = @class.from_s(cert.to_pem)
+ certificate.subject_alt_names.
+ should =~ ['DNS:foo', 'DNS:bar', 'DNS:baz', 'DNS:quux']
end
it "should return an empty list of names if the extension is absent" do
- cert = Puppet::SSL::CertificateFactory.new('client', @csr, @csr, 14).result
+ key = Puppet::SSL::Key.new('quux')
+ key.generate
+
+ csr = Puppet::SSL::CertificateRequest.new('quux')
+ csr.generate(key)
- @certificate = @class.from_s(cert.to_pem)
+ raw_csr = csr.content
- @certificate.alternate_names.should == []
+ cert = Puppet::SSL::CertificateFactory.build('client', csr, raw_csr, 14)
+ certificate = @class.from_s(cert.to_pem)
+ certificate.subject_alt_names.should be_empty
end
end
it "should return a nil expiration if there is no actual certificate" do
@certificate.stubs(:content).returns nil
@certificate.expiration.should be_nil
end
it "should use the expiration of the certificate as its expiration date" do
cert = stub 'cert'
@certificate.stubs(:content).returns cert
cert.expects(:not_after).returns "sometime"
@certificate.expiration.should == "sometime"
end
it "should be able to read certificates from disk" do
path = "/my/path"
File.expects(:read).with(path).returns("my certificate")
certificate = mock 'certificate'
OpenSSL::X509::Certificate.expects(:new).with("my certificate").returns(certificate)
@certificate.read(path).should equal(certificate)
@certificate.content.should equal(certificate)
end
it "should have a :to_text method that it delegates to the actual key" do
real_certificate = mock 'certificate'
real_certificate.expects(:to_text).returns "certificatetext"
@certificate.content = real_certificate
@certificate.to_text.should == "certificatetext"
end
end
end
diff --git a/spec/unit/ssl/host_spec.rb b/spec/unit/ssl/host_spec.rb
index dac45e9a1..95b605bf7 100755
--- a/spec/unit/ssl/host_spec.rb
+++ b/spec/unit/ssl/host_spec.rb
@@ -1,798 +1,837 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'puppet/ssl/host'
-require 'puppet/sslcertificates'
-require 'puppet/sslcertificates/ca'
describe Puppet::SSL::Host do
include PuppetSpec::Files
before do
Puppet::SSL::Host.indirection.terminus_class = :file
# Get a safe temporary file
dir = tmpdir("ssl_host_testing")
Puppet.settings[:confdir] = dir
Puppet.settings[:vardir] = dir
Puppet.settings.use :main, :ssl
@host = Puppet::SSL::Host.new("myname")
end
after do
# Cleaned out any cached localhost instance.
Puppet::SSL::Host.reset
Puppet::SSL::Host.ca_location = :none
end
it "should use any provided name as its name" do
@host.name.should == "myname"
end
it "should retrieve its public key from its private key" do
realkey = mock 'realkey'
key = stub 'key', :content => realkey
Puppet::SSL::Key.indirection.stubs(:find).returns(key)
pubkey = mock 'public_key'
realkey.expects(:public_key).returns pubkey
@host.public_key.should equal(pubkey)
end
it "should default to being a non-ca host" do
@host.ca?.should be_false
end
it "should be a ca host if its name matches the CA_NAME" do
Puppet::SSL::Host.stubs(:ca_name).returns "yayca"
Puppet::SSL::Host.new("yayca").should be_ca
end
it "should have a method for determining the CA location" do
Puppet::SSL::Host.should respond_to(:ca_location)
end
it "should have a method for specifying the CA location" do
Puppet::SSL::Host.should respond_to(:ca_location=)
end
it "should have a method for retrieving the default ssl host" do
Puppet::SSL::Host.should respond_to(:ca_location=)
end
it "should have a method for producing an instance to manage the local host's keys" do
Puppet::SSL::Host.should respond_to(:localhost)
end
it "should allow to reset localhost" do
previous_host = Puppet::SSL::Host.localhost
Puppet::SSL::Host.reset
Puppet::SSL::Host.localhost.should_not == previous_host
end
it "should generate the certificate for the localhost instance if no certificate is available" do
host = stub 'host', :key => nil
Puppet::SSL::Host.expects(:new).returns host
host.expects(:certificate).returns nil
host.expects(:generate)
Puppet::SSL::Host.localhost.should equal(host)
end
+ it "should create a localhost cert if no cert is available and it is a CA with autosign and it is using DNS alt names", :unless => Puppet.features.microsoft_windows? do
+ Puppet[:autosign] = true
+ Puppet[:confdir] = tmpdir('conf')
+ Puppet[:dns_alt_names] = "foo,bar,baz"
+ ca = Puppet::SSL::CertificateAuthority.new
+ Puppet::SSL::CertificateAuthority.stubs(:instance).returns ca
+
+ localhost = Puppet::SSL::Host.localhost
+ cert = localhost.certificate
+
+ cert.should be_a(Puppet::SSL::Certificate)
+ cert.subject_alt_names.should =~ %W[DNS:#{Puppet[:certname]} DNS:foo DNS:bar DNS:baz]
+ end
+
+ context "with dns_alt_names" do
+ before :each do
+ Puppet[:dns_alt_names] = 'one, two'
+
+ @key = stub('key content')
+ key = stub('key', :generate => true, :content => @key)
+ Puppet::SSL::Key.stubs(:new).returns key
+ Puppet::SSL::Key.indirection.stubs(:save).with(key)
+
+ @cr = stub('certificate request')
+ Puppet::SSL::CertificateRequest.stubs(:new).returns @cr
+ Puppet::SSL::CertificateRequest.indirection.stubs(:save).with(@cr)
+ end
+
+ it "should not include subjectAltName if not the local node" do
+ @cr.expects(:generate).with(@key, {})
+
+ Puppet::SSL::Host.new('not-the-' + Puppet[:certname]).generate
+ end
+
+ it "should include subjectAltName if I am a CA" do
+ @cr.expects(:generate).
+ with(@key, { :dns_alt_names => Puppet[:dns_alt_names] })
+
+ Puppet::SSL::Host.localhost
+ end
+ end
+
it "should always read the key for the localhost instance in from disk" do
host = stub 'host', :certificate => "eh"
Puppet::SSL::Host.expects(:new).returns host
host.expects(:key)
Puppet::SSL::Host.localhost
end
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?)
end
it "should consider the certificate invalid if it cannot find a key" do
host = Puppet::SSL::Host.new("foo")
host.expects(:key).returns nil
host.should_not be_certificate_matches_key
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(:certificate).returns nil
host.should_not be_certificate_matches_key
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
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
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
end
describe "when specifying the CA location" do
it "should support the location ':local'" do
lambda { Puppet::SSL::Host.ca_location = :local }.should_not raise_error
end
it "should support the location ':remote'" do
lambda { Puppet::SSL::Host.ca_location = :remote }.should_not raise_error
end
it "should support the location ':none'" do
lambda { Puppet::SSL::Host.ca_location = :none }.should_not raise_error
end
it "should support the location ':only'" do
lambda { Puppet::SSL::Host.ca_location = :only }.should_not raise_error
end
it "should not support other modes" do
lambda { Puppet::SSL::Host.ca_location = :whatever }.should raise_error(ArgumentError)
end
describe "as 'local'" do
before do
Puppet::SSL::Host.ca_location = :local
end
it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do
Puppet::SSL::Certificate.indirection.cache_class.should == :file
Puppet::SSL::CertificateRequest.indirection.cache_class.should == :file
Puppet::SSL::CertificateRevocationList.indirection.cache_class.should == :file
end
it "should set the terminus class for Key and Host as :file" do
Puppet::SSL::Key.indirection.terminus_class.should == :file
Puppet::SSL::Host.indirection.terminus_class.should == :file
end
it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :ca" do
Puppet::SSL::Certificate.indirection.terminus_class.should == :ca
Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :ca
Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :ca
end
end
describe "as 'remote'" do
before do
Puppet::SSL::Host.ca_location = :remote
end
it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do
Puppet::SSL::Certificate.indirection.cache_class.should == :file
Puppet::SSL::CertificateRequest.indirection.cache_class.should == :file
Puppet::SSL::CertificateRevocationList.indirection.cache_class.should == :file
end
it "should set the terminus class for Key as :file" do
Puppet::SSL::Key.indirection.terminus_class.should == :file
end
it "should set the terminus class for Host, Certificate, CertificateRevocationList, and CertificateRequest as :rest" do
Puppet::SSL::Host.indirection.terminus_class.should == :rest
Puppet::SSL::Certificate.indirection.terminus_class.should == :rest
Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :rest
Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :rest
end
end
describe "as 'only'" do
before do
Puppet::SSL::Host.ca_location = :only
end
it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :ca" do
Puppet::SSL::Key.indirection.terminus_class.should == :ca
Puppet::SSL::Certificate.indirection.terminus_class.should == :ca
Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :ca
Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :ca
end
it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest to nil" do
Puppet::SSL::Certificate.indirection.cache_class.should be_nil
Puppet::SSL::CertificateRequest.indirection.cache_class.should be_nil
Puppet::SSL::CertificateRevocationList.indirection.cache_class.should be_nil
end
it "should set the terminus class for Host to :file" do
Puppet::SSL::Host.indirection.terminus_class.should == :file
end
end
describe "as 'none'" do
before do
Puppet::SSL::Host.ca_location = :none
end
it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :file" do
Puppet::SSL::Key.indirection.terminus_class.should == :file
Puppet::SSL::Certificate.indirection.terminus_class.should == :file
Puppet::SSL::CertificateRequest.indirection.terminus_class.should == :file
Puppet::SSL::CertificateRevocationList.indirection.terminus_class.should == :file
end
it "should set the terminus class for Host to 'none'" do
lambda { Puppet::SSL::Host.indirection.terminus_class }.should raise_error(Puppet::DevError)
end
end
end
it "should have a class method for destroying all files related to a given host" do
Puppet::SSL::Host.should respond_to(:destroy)
end
describe "when destroying a host's SSL files" do
before do
Puppet::SSL::Key.indirection.stubs(:destroy).returns false
Puppet::SSL::Certificate.indirection.stubs(:destroy).returns false
Puppet::SSL::CertificateRequest.indirection.stubs(:destroy).returns false
end
it "should destroy its certificate, certificate request, and key" do
Puppet::SSL::Key.indirection.expects(:destroy).with("myhost")
Puppet::SSL::Certificate.indirection.expects(:destroy).with("myhost")
Puppet::SSL::CertificateRequest.indirection.expects(:destroy).with("myhost")
Puppet::SSL::Host.destroy("myhost")
end
it "should return true if any of the classes returned true" do
Puppet::SSL::Certificate.indirection.expects(:destroy).with("myhost").returns true
Puppet::SSL::Host.destroy("myhost").should be_true
end
it "should report that nothing was deleted if none of the classes returned true" do
Puppet::SSL::Host.destroy("myhost").should == "Nothing was deleted"
end
end
describe "when initializing" do
it "should default its name to the :certname setting" do
Puppet.settings.expects(:value).with(:certname).returns "myname"
Puppet::SSL::Host.new.name.should == "myname"
end
it "should downcase a passed in name" do
Puppet::SSL::Host.new("Host.Domain.Com").name.should == "host.domain.com"
end
it "should downcase the certname if it's used" do
Puppet.settings.expects(:value).with(:certname).returns "Host.Domain.Com"
Puppet::SSL::Host.new.name.should == "host.domain.com"
end
it "should indicate that it is a CA host if its name matches the ca_name constant" do
Puppet::SSL::Host.stubs(:ca_name).returns "myca"
Puppet::SSL::Host.new("myca").should be_ca
end
end
describe "when managing its private key" do
before do
@realkey = "mykey"
@key = Puppet::SSL::Key.new("mykey")
@key.content = @realkey
end
it "should return nil if the key is not set and cannot be found" do
Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(nil)
@host.key.should be_nil
end
it "should find the key in the Key class and return the Puppet instance" do
Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(@key)
@host.key.should equal(@key)
end
it "should be able to generate and save a new key" do
Puppet::SSL::Key.expects(:new).with("myname").returns(@key)
@key.expects(:generate)
Puppet::SSL::Key.indirection.expects(:save)
@host.generate_key.should be_true
@host.key.should equal(@key)
end
it "should not retain keys that could not be saved" do
Puppet::SSL::Key.expects(:new).with("myname").returns(@key)
@key.stubs(:generate)
Puppet::SSL::Key.indirection.expects(:save).raises "eh"
lambda { @host.generate_key }.should raise_error
@host.key.should be_nil
end
it "should return any previously found key without requerying" do
Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(@key).once
@host.key.should equal(@key)
@host.key.should equal(@key)
end
end
describe "when managing its certificate request" do
before do
@realrequest = "real request"
@request = Puppet::SSL::CertificateRequest.new("myname")
@request.content = @realrequest
end
it "should return nil if the key is not set and cannot be found" do
Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns(nil)
@host.certificate_request.should be_nil
end
it "should find the request in the Key class and return it and return the Puppet SSL request" do
Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns @request
@host.certificate_request.should equal(@request)
end
it "should generate a new key when generating the cert request if no key exists" do
Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request
key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
@host.expects(:key).times(2).returns(nil).then.returns(key)
@host.expects(:generate_key).returns(key)
@request.stubs(:generate)
Puppet::SSL::CertificateRequest.indirection.stubs(:save)
@host.generate_certificate_request
end
it "should be able to generate and save a new request using the private key" do
Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request
key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
@host.stubs(:key).returns(key)
- @request.expects(:generate).with("mycontent")
+ @request.expects(:generate).with("mycontent", {})
Puppet::SSL::CertificateRequest.indirection.expects(:save).with(@request)
@host.generate_certificate_request.should be_true
@host.certificate_request.should equal(@request)
end
it "should return any previously found request without requerying" do
Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns(@request).once
@host.certificate_request.should equal(@request)
@host.certificate_request.should equal(@request)
end
it "should not keep its certificate request in memory if the request cannot be saved" do
Puppet::SSL::CertificateRequest.expects(:new).with("myname").returns @request
key = stub 'key', :public_key => mock("public_key"), :content => "mycontent"
@host.stubs(:key).returns(key)
@request.stubs(:generate)
@request.stubs(:name).returns("myname")
terminus = stub 'terminus'
Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus)
terminus.expects(:save).with { |req| req.instance == @request && req.key == "myname" }.raises "eh"
lambda { @host.generate_certificate_request }.should raise_error
@host.instance_eval { @certificate_request }.should be_nil
end
end
describe "when managing its certificate" do
before do
@realcert = mock 'certificate'
@cert = stub 'cert', :content => @realcert
@host.stubs(:key).returns mock("key")
@host.stubs(:certificate_matches_key?).returns true
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
it "should not find the CA certificate if it is the CA host" do
@host.expects(:ca?).returns true
Puppet::SSL::Certificate.indirection.stubs(:find)
Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).never
@host.certificate
end
it "should return nil if it cannot find a CA certificate" do
Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns nil
Puppet::SSL::Certificate.indirection.expects(:find).with("myname").never
@host.certificate.should be_nil
end
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
@host.certificate.should equal(@cert)
@host.certificate.should equal(@cert)
end
end
it "should have a method for listing certificate hosts" do
Puppet::SSL::Host.should respond_to(:search)
end
describe "when listing certificate hosts" do
it "should default to listing all clients with any file types" do
Puppet::SSL::Key.indirection.expects(:search).returns []
Puppet::SSL::Certificate.indirection.expects(:search).returns []
Puppet::SSL::CertificateRequest.indirection.expects(:search).returns []
Puppet::SSL::Host.search
end
it "should be able to list only clients with a key" do
Puppet::SSL::Key.indirection.expects(:search).returns []
Puppet::SSL::Certificate.indirection.expects(:search).never
Puppet::SSL::CertificateRequest.indirection.expects(:search).never
Puppet::SSL::Host.search :for => Puppet::SSL::Key
end
it "should be able to list only clients with a certificate" do
Puppet::SSL::Key.indirection.expects(:search).never
Puppet::SSL::Certificate.indirection.expects(:search).returns []
Puppet::SSL::CertificateRequest.indirection.expects(:search).never
Puppet::SSL::Host.search :for => Puppet::SSL::Certificate
end
it "should be able to list only clients with a certificate request" do
Puppet::SSL::Key.indirection.expects(:search).never
Puppet::SSL::Certificate.indirection.expects(:search).never
Puppet::SSL::CertificateRequest.indirection.expects(:search).returns []
Puppet::SSL::Host.search :for => Puppet::SSL::CertificateRequest
end
it "should return a Host instance created with the name of each found instance", :'fails_on_ruby_1.9.2' => true do
key = stub 'key', :name => "key"
cert = stub 'cert', :name => "cert"
csr = stub 'csr', :name => "csr"
Puppet::SSL::Key.indirection.expects(:search).returns [key]
Puppet::SSL::Certificate.indirection.expects(:search).returns [cert]
Puppet::SSL::CertificateRequest.indirection.expects(:search).returns [csr]
returned = []
%w{key cert csr}.each do |name|
result = mock(name)
returned << result
Puppet::SSL::Host.expects(:new).with(name).returns result
end
result = Puppet::SSL::Host.search
returned.each do |r|
result.should be_include(r)
end
end
end
it "should have a method for generating all necessary files" do
Puppet::SSL::Host.new("me").should respond_to(:generate)
end
describe "when generating files" do
before do
@host = Puppet::SSL::Host.new("me")
@host.stubs(:generate_key)
@host.stubs(:generate_certificate_request)
end
it "should generate a key if one is not present" do
@host.stubs(:key).returns nil
@host.expects(:generate_key)
@host.generate
end
it "should generate a certificate request if one is not present" do
@host.expects(:certificate_request).returns nil
@host.expects(:generate_certificate_request)
@host.generate
end
describe "and it can create a certificate authority" do
before do
@ca = mock 'ca'
Puppet::SSL::CertificateAuthority.stubs(:instance).returns @ca
end
it "should use the CA to sign its certificate request if it does not have a certificate" do
@host.expects(:certificate).returns nil
- @ca.expects(:sign).with(@host.name)
+ @ca.expects(:sign).with(@host.name, true)
@host.generate
end
end
describe "and it cannot create a certificate authority" do
before do
Puppet::SSL::CertificateAuthority.stubs(:instance).returns nil
end
it "should seek its certificate" do
@host.expects(:certificate)
@host.generate
end
end
end
it "should have a method for creating an SSL store" do
Puppet::SSL::Host.new("me").should respond_to(:ssl_store)
end
it "should always return the same store" do
host = Puppet::SSL::Host.new("foo")
store = mock 'store'
store.stub_everything
OpenSSL::X509::Store.expects(:new).returns store
host.ssl_store.should equal(host.ssl_store)
end
describe "when creating an SSL store" do
before do
@host = Puppet::SSL::Host.new("me")
@store = mock 'store'
@store.stub_everything
OpenSSL::X509::Store.stubs(:new).returns @store
Puppet.settings.stubs(:value).with(:localcacert).returns "ssl_host_testing"
Puppet::SSL::CertificateRevocationList.indirection.stubs(:find).returns(nil)
end
it "should accept a purpose" do
@store.expects(:purpose=).with "my special purpose"
@host.ssl_store("my special purpose")
end
it "should default to OpenSSL::X509::PURPOSE_ANY as the purpose" do
@store.expects(:purpose=).with OpenSSL::X509::PURPOSE_ANY
@host.ssl_store
end
it "should add the local CA cert file" do
Puppet.settings.stubs(:value).with(:localcacert).returns "/ca/cert/file"
@store.expects(:add_file).with "/ca/cert/file"
@host.ssl_store
end
describe "and a CRL is available" do
before do
@crl = stub 'crl', :content => "real_crl"
Puppet::SSL::CertificateRevocationList.indirection.stubs(:find).returns @crl
Puppet.settings.stubs(:value).with(:certificate_revocation).returns true
end
it "should add the CRL" do
@store.expects(:add_crl).with "real_crl"
@host.ssl_store
end
it "should set the flags to OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK" do
@store.expects(:flags=).with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK
@host.ssl_store
end
end
end
describe "when waiting for a cert" do
before do
@host = Puppet::SSL::Host.new("me")
end
it "should generate its certificate request and attempt to read the certificate again if no certificate is found" do
@host.expects(:certificate).times(2).returns(nil).then.returns "foo"
@host.expects(:generate)
@host.wait_for_cert(1)
end
it "should catch and log errors during CSR saving" do
@host.expects(:certificate).times(2).returns(nil).then.returns "foo"
@host.expects(:generate).raises(RuntimeError).then.returns nil
@host.stubs(:sleep)
@host.wait_for_cert(1)
end
it "should sleep and retry after failures saving the CSR if waitforcert is enabled" do
@host.expects(:certificate).times(2).returns(nil).then.returns "foo"
@host.expects(:generate).raises(RuntimeError).then.returns nil
@host.expects(:sleep).with(1)
@host.wait_for_cert(1)
end
it "should exit after failures saving the CSR of waitforcert is disabled" do
@host.expects(:certificate).returns(nil)
@host.expects(:generate).raises(RuntimeError)
@host.expects(:puts)
expect { @host.wait_for_cert(0) }.to exit_with 1
end
it "should exit if the wait time is 0 and it can neither find nor retrieve a certificate" do
@host.stubs(:certificate).returns nil
@host.expects(:generate)
@host.expects(:puts)
expect { @host.wait_for_cert(0) }.to exit_with 1
end
it "should sleep for the specified amount of time if no certificate is found after generating its certificate request" do
@host.expects(:certificate).times(3).returns(nil).then.returns(nil).then.returns "foo"
@host.expects(:generate)
@host.expects(:sleep).with(1)
@host.wait_for_cert(1)
end
it "should catch and log exceptions during certificate retrieval" do
@host.expects(:certificate).times(3).returns(nil).then.raises(RuntimeError).then.returns("foo")
@host.stubs(:generate)
@host.stubs(:sleep)
Puppet.expects(:err)
@host.wait_for_cert(1)
end
end
describe "when handling PSON", :unless => Puppet.features.microsoft_windows? do
include PuppetSpec::Files
before do
Puppet[:vardir] = tmpdir("ssl_test_vardir")
Puppet[:ssldir] = tmpdir("ssl_test_ssldir")
- Puppet::SSLCertificates::CA.new.mkrootcert
# localcacert is where each client stores the CA certificate
# cacert is where the master stores the CA certificate
# Since we need to play the role of both for testing we need them to be the same and exist
Puppet[:cacert] = Puppet[:localcacert]
@ca=Puppet::SSL::CertificateAuthority.new
end
describe "when converting to PSON" do
it "should be able to identify a host with an unsigned certificate request" do
host = Puppet::SSL::Host.new("bazinga")
host.generate_certificate_request
pson_hash = {
"fingerprint" => host.certificate_request.fingerprint,
"desired_state" => 'requested',
"name" => host.name
}
result = PSON.parse(Puppet::SSL::Host.new(host.name).to_pson)
result["fingerprint"].should == pson_hash["fingerprint"]
result["name"].should == pson_hash["name"]
result["state"].should == pson_hash["desired_state"]
end
it "should be able to identify a host with a signed certificate" do
host = Puppet::SSL::Host.new("bazinga")
host.generate_certificate_request
@ca.sign(host.name)
pson_hash = {
"fingerprint" => Puppet::SSL::Certificate.indirection.find(host.name).fingerprint,
"desired_state" => 'signed',
"name" => host.name,
}
result = PSON.parse(Puppet::SSL::Host.new(host.name).to_pson)
result["fingerprint"].should == pson_hash["fingerprint"]
result["name"].should == pson_hash["name"]
result["state"].should == pson_hash["desired_state"]
end
it "should be able to identify a host with a revoked certificate" do
host = Puppet::SSL::Host.new("bazinga")
host.generate_certificate_request
@ca.sign(host.name)
@ca.revoke(host.name)
pson_hash = {
"fingerprint" => Puppet::SSL::Certificate.indirection.find(host.name).fingerprint,
"desired_state" => 'revoked',
"name" => host.name,
}
result = PSON.parse(Puppet::SSL::Host.new(host.name).to_pson)
result["fingerprint"].should == pson_hash["fingerprint"]
result["name"].should == pson_hash["name"]
result["state"].should == pson_hash["desired_state"]
end
end
describe "when converting from PSON" do
it "should return a Puppet::SSL::Host object with the specified desired state" do
host = Puppet::SSL::Host.new("bazinga")
host.desired_state="signed"
pson_hash = {
"name" => host.name,
"desired_state" => host.desired_state,
}
generated_host = Puppet::SSL::Host.from_pson(pson_hash)
generated_host.desired_state.should == host.desired_state
generated_host.name.should == host.name
end
end
end
end
diff --git a/spec/unit/sslcertificates/ca_spec.rb b/spec/unit/sslcertificates/ca_spec.rb
deleted file mode 100755
index 7a687b825..000000000
--- a/spec/unit/sslcertificates/ca_spec.rb
+++ /dev/null
@@ -1,106 +0,0 @@
-#!/usr/bin/env rspec
-require 'spec_helper'
-
-require 'puppet'
-require 'puppet/sslcertificates'
-require 'puppet/sslcertificates/ca'
-
-describe Puppet::SSLCertificates::CA, :unless => Puppet.features.microsoft_windows? do
- include PuppetSpec::Files
-
- before :all do
- @hosts = %w{host.domain.com Other.Testing.Com}
- end
-
- before :each do
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- dir = tmpdir("ca_testing")
-
- Puppet.settings[:confdir] = dir
- Puppet.settings[:vardir] = dir
-
- @ca = Puppet::SSLCertificates::CA.new
- end
-
- describe 'when cleaning' do
- it 'should remove associated files' do
- dirs = [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir]
-
- @hosts.each do |host|
- files = []
- dirs.each do |dir|
- dir = Puppet[dir]
-
- # Case insensitivity is handled through downcasing
- file = File.join(dir, host.downcase + '.pem')
-
- File.open(file, "w") do |f|
- f.puts "testing"
- end
-
- files << file
- end
-
- lambda { @ca.clean(host) }.should_not raise_error
-
- files.reject {|f| ! File.exists?(f)}.should be_empty
- end
- end
- end
-
- describe 'when mapping hosts to files' do
- it 'should correctly return the certfile' do
- @hosts.each do |host|
- value = nil
- lambda { value = @ca.host2certfile host }.should_not raise_error
-
- File.join(Puppet[:signeddir], host.downcase + '.pem').should == value
- end
- end
-
- it 'should correctly return the csrfile' do
- @hosts.each do |host|
- value = nil
- lambda { value = @ca.host2csrfile host }.should_not raise_error
-
- File.join(Puppet[:csrdir], host.downcase + '.pem').should == value
- end
- end
- end
-
- describe 'when listing' do
- it 'should find all csr' do
- list = []
-
- # Make some fake CSRs
- @hosts.each do |host|
- file = File.join(Puppet[:csrdir], host.downcase + '.pem')
- File.open(file, 'w') { |f| f.puts "yay" }
- list << host.downcase
- end
-
- @ca.list.sort.should == list.sort
- end
- end
-
- describe 'when creating a root certificate' do
- before :each do
- lambda { @ca.mkrootcert }.should_not raise_exception
- end
-
- it 'should store the public key' do
- File.exists?(Puppet[:capub]).should be_true
- end
-
- it 'should prepend "Puppet CA: " to the fqdn as the ca_name by default' do
- host_mock_fact = mock()
- host_mock_fact.expects(:value).returns('myhost')
- domain_mock_fact = mock()
- domain_mock_fact.expects(:value).returns('puppetlabs.lan')
- Facter.stubs(:[]).with('hostname').returns(host_mock_fact)
- Facter.stubs(:[]).with('domain').returns(domain_mock_fact)
-
- @ca.mkrootcert.name.should == 'Puppet CA: myhost.puppetlabs.lan'
- end
- end
-end
diff --git a/spec/unit/util/reference_spec.rb b/spec/unit/util/reference_spec.rb
new file mode 100644
index 000000000..219a673ef
--- /dev/null
+++ b/spec/unit/util/reference_spec.rb
@@ -0,0 +1,29 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+require 'puppet/util/reference'
+
+describe Puppet::Util::Reference do
+ it "should create valid Markdown extension definition lists" do
+ my_fragment = nil
+ 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.
+
+We should be able to handle multi-paragraph definitions.
+ 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.
+
+ We should be able to handle multi-paragraph definitions.
+
+ EOT
+ end
+
+end
\ No newline at end of file
diff --git a/spec/unit/util/settings_spec.rb b/spec/unit/util/settings_spec.rb
index 69c117f28..26e69a3ac 100755
--- a/spec/unit/util/settings_spec.rb
+++ b/spec/unit/util/settings_spec.rb
@@ -1,1131 +1,1141 @@
#!/usr/bin/env rspec
require 'spec_helper'
require 'ostruct'
describe Puppet::Util::Settings do
include PuppetSpec::Files
describe "when specifying defaults" do
before do
@settings = Puppet::Util::Settings.new
end
it "should start with no defined parameters" do
@settings.params.length.should == 0
end
it "should allow specification of default values associated with a section as an array" do
@settings.setdefaults(:section, :myvalue => ["defaultval", "my description"])
end
it "should not allow duplicate parameter specifications" do
@settings.setdefaults(:section, :myvalue => ["a", "b"])
lambda { @settings.setdefaults(:section, :myvalue => ["c", "d"]) }.should raise_error(ArgumentError)
end
it "should allow specification of default values associated with a section as a hash" do
@settings.setdefaults(:section, :myvalue => {:default => "defaultval", :desc => "my description"})
end
it "should consider defined parameters to be valid" do
@settings.setdefaults(:section, :myvalue => ["defaultval", "my description"])
@settings.valid?(:myvalue).should be_true
end
it "should require a description when defaults are specified with an array" do
lambda { @settings.setdefaults(:section, :myvalue => ["a value"]) }.should raise_error(ArgumentError)
end
it "should require a description when defaults are specified with a hash" do
lambda { @settings.setdefaults(:section, :myvalue => {:default => "a value"}) }.should raise_error(ArgumentError)
end
it "should raise an error if we can't guess the type" do
lambda { @settings.setdefaults(:section, :myvalue => {:default => Object.new, :desc => "An impossible object"}) }.should raise_error(ArgumentError)
end
it "should support specifying owner, group, and mode when specifying files" do
@settings.setdefaults(:section, :myvalue => {:default => "/some/file", :owner => "service", :mode => "boo", :group => "service", :desc => "whatever"})
end
it "should support specifying a short name" do
@settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"})
end
it "should support specifying the setting type" do
@settings.setdefaults(:section, :myvalue => {:default => "/w", :desc => "b", :type => :setting})
@settings.setting(:myvalue).should be_instance_of(Puppet::Util::Settings::Setting)
end
it "should fail if an invalid setting type is specified" do
lambda { @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :type => :foo}) }.should raise_error(ArgumentError)
end
it "should fail when short names conflict" do
@settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"})
lambda { @settings.setdefaults(:section, :myvalue => {:default => "w", :desc => "b", :short => "m"}) }.should raise_error(ArgumentError)
end
end
describe "when setting values" do
before do
@settings = Puppet::Util::Settings.new
@settings.setdefaults :main, :myval => ["val", "desc"]
@settings.setdefaults :main, :bool => [true, "desc"]
end
it "should provide a method for setting values from other objects" do
@settings[:myval] = "something else"
@settings[:myval].should == "something else"
end
it "should support a getopt-specific mechanism for setting values" do
@settings.handlearg("--myval", "newval")
@settings[:myval].should == "newval"
end
it "should support a getopt-specific mechanism for turning booleans off" do
@settings[:bool] = true
@settings.handlearg("--no-bool", "")
@settings[:bool].should == false
end
it "should support a getopt-specific mechanism for turning booleans on" do
# Turn it off first
@settings[:bool] = false
@settings.handlearg("--bool", "")
@settings[:bool].should == true
end
it "should consider a cli setting with no argument to be a boolean" do
# Turn it off first
@settings[:bool] = false
@settings.handlearg("--bool")
@settings[:bool].should == true
end
it "should consider a cli setting with an empty string as an argument to be a boolean, if the setting itself is a boolean" do
# Turn it off first
@settings[:bool] = false
@settings.handlearg("--bool", "")
@settings[:bool].should == true
end
it "should consider a cli setting with an empty string as an argument to be an empty argument, if the setting itself is not a boolean" do
@settings[:myval] = "bob"
@settings.handlearg("--myval", "")
@settings[:myval].should == ""
end
it "should consider a cli setting with a boolean as an argument to be a boolean" do
# Turn it off first
@settings[:bool] = false
@settings.handlearg("--bool", "true")
@settings[:bool].should == true
end
it "should not consider a cli setting of a non boolean with a boolean as an argument to be a boolean" do
# Turn it off first
@settings[:myval] = "bob"
@settings.handlearg("--no-myval", "")
@settings[:myval].should == ""
end
+ it "should flag settings from the CLI" do
+ @settings.handlearg("--myval")
+ @settings.setting(:myval).setbycli.should be_true
+ end
+
+ it "should not flag settings memory" do
+ @settings[:myval] = "12"
+ @settings.setting(:myval).setbycli.should be_false
+ end
+
it "should clear the cache when setting getopt-specific values" do
@settings.setdefaults :mysection, :one => ["whah", "yay"], :two => ["$one yay", "bah"]
@settings[:two].should == "whah yay"
@settings.handlearg("--one", "else")
@settings[:two].should == "else yay"
end
it "should not clear other values when setting getopt-specific values" do
@settings[:myval] = "yay"
@settings.handlearg("--no-bool", "")
@settings[:myval].should == "yay"
end
it "should clear the list of used sections" do
@settings.expects(:clearused)
@settings[:myval] = "yay"
end
it "should call passed blocks when values are set" do
values = []
@settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :hook => lambda { |v| values << v }})
values.should == []
@settings[:hooker] = "something"
values.should == %w{something}
end
it "should call passed blocks when values are set via the command line" do
values = []
@settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :hook => lambda { |v| values << v }})
values.should == []
@settings.handlearg("--hooker", "yay")
values.should == %w{yay}
end
it "should provide an option to call passed blocks during definition" do
values = []
@settings.setdefaults(:section, :hooker => {:default => "yay", :desc => "boo", :call_on_define => true, :hook => lambda { |v| values << v }})
values.should == %w{yay}
end
it "should pass the fully interpolated value to the hook when called on definition" do
values = []
@settings.setdefaults(:section, :one => ["test", "a"])
@settings.setdefaults(:section, :hooker => {:default => "$one/yay", :desc => "boo", :call_on_define => true, :hook => lambda { |v| values << v }})
values.should == %w{test/yay}
end
it "should munge values using the setting-specific methods" do
@settings[:bool] = "false"
@settings[:bool].should == false
end
it "should prefer cli values to values set in Ruby code" do
@settings.handlearg("--myval", "cliarg")
@settings[:myval] = "memarg"
@settings[:myval].should == "cliarg"
end
it "should clear the list of environments" do
Puppet::Node::Environment.expects(:clear).at_least(1)
@settings[:myval] = "memarg"
end
it "should raise an error if we try to set 'name'" do
lambda{ @settings[:name] = "foo" }.should raise_error(ArgumentError)
end
it "should raise an error if we try to set 'run_mode'" do
lambda{ @settings[:run_mode] = "foo" }.should raise_error(ArgumentError)
end
it "should warn and use [master] if we ask for [puppetmasterd]" do
Puppet.expects(:warning)
@settings.set_value(:myval, "foo", :puppetmasterd)
@settings.stubs(:run_mode).returns(:master)
@settings.value(:myval).should == "foo"
end
it "should warn and use [agent] if we ask for [puppetd]" do
Puppet.expects(:warning)
@settings.set_value(:myval, "foo", :puppetd)
@settings.stubs(:run_mode).returns(:agent)
@settings.value(:myval).should == "foo"
end
end
describe "when returning values" do
before do
@settings = Puppet::Util::Settings.new
@settings.setdefaults :section, :config => ["/my/file", "eh"], :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"], :four => ["$two $three FOUR", "d"]
FileTest.stubs(:exist?).returns true
end
it "should provide a mechanism for returning set values" do
@settings[:one] = "other"
@settings[:one].should == "other"
end
it "should interpolate default values for other parameters into returned parameter values" do
@settings[:one].should == "ONE"
@settings[:two].should == "ONE TWO"
@settings[:three].should == "ONE ONE TWO THREE"
end
it "should interpolate default values that themselves need to be interpolated" do
@settings[:four].should == "ONE TWO ONE ONE TWO THREE FOUR"
end
it "should provide a method for returning uninterpolated values" do
@settings[:two] = "$one tw0"
@settings.uninterpolated_value(:two).should == "$one tw0"
@settings.uninterpolated_value(:four).should == "$two $three FOUR"
end
it "should interpolate set values for other parameters into returned parameter values" do
@settings[:one] = "on3"
@settings[:two] = "$one tw0"
@settings[:three] = "$one $two thr33"
@settings[:four] = "$one $two $three f0ur"
@settings[:one].should == "on3"
@settings[:two].should == "on3 tw0"
@settings[:three].should == "on3 on3 tw0 thr33"
@settings[:four].should == "on3 on3 tw0 on3 on3 tw0 thr33 f0ur"
end
it "should not cache interpolated values such that stale information is returned" do
@settings[:two].should == "ONE TWO"
@settings[:one] = "one"
@settings[:two].should == "one TWO"
end
it "should not cache values such that information from one environment is returned for another environment" do
text = "[env1]\none = oneval\n[env2]\none = twoval\n"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings.value(:one, "env1").should == "oneval"
@settings.value(:one, "env2").should == "twoval"
end
it "should have a run_mode that defaults to user" do
@settings.run_mode.should == :user
end
end
describe "when choosing which value to return" do
before do
@settings = Puppet::Util::Settings.new
@settings.setdefaults :section,
:config => ["/my/file", "a"],
:one => ["ONE", "a"],
:two => ["TWO", "b"]
FileTest.stubs(:exist?).returns true
Puppet.stubs(:run_mode).returns stub('run_mode', :name => :mymode)
end
it "should return default values if no values have been set" do
@settings[:one].should == "ONE"
end
it "should return values set on the cli before values set in the configuration file" do
text = "[main]\none = fileval\n"
@settings.stubs(:read_file).returns(text)
@settings.handlearg("--one", "clival")
@settings.parse
@settings[:one].should == "clival"
end
it "should return values set on the cli before values set in Ruby" do
@settings[:one] = "rubyval"
@settings.handlearg("--one", "clival")
@settings[:one].should == "clival"
end
it "should return values set in the mode-specific section before values set in the main section" do
text = "[main]\none = mainval\n[mymode]\none = modeval\n"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings[:one].should == "modeval"
end
it "should not return values outside of its search path" do
text = "[other]\none = oval\n"
file = "/some/file"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings[:one].should == "ONE"
end
it "should return values in a specified environment" do
text = "[env]\none = envval\n"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings.value(:one, "env").should == "envval"
end
it 'should use the current environment for $environment' do
@settings.setdefaults :main, :myval => ["$environment/foo", "mydocs"]
@settings.value(:myval, "myenv").should == "myenv/foo"
end
it "should interpolate found values using the current environment" do
text = "[main]\none = mainval\n[myname]\none = nameval\ntwo = $one/two\n"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings.value(:two, "myname").should == "nameval/two"
end
it "should return values in a specified environment before values in the main or name sections" do
text = "[env]\none = envval\n[main]\none = mainval\n[myname]\none = nameval\n"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings.value(:one, "env").should == "envval"
end
end
describe "when parsing its configuration" do
before do
@settings = Puppet::Util::Settings.new
@settings.stubs(:service_user_available?).returns true
@file = "/some/file"
@settings.setdefaults :section, :user => ["suser", "doc"], :group => ["sgroup", "doc"]
@settings.setdefaults :section, :config => ["/some/file", "eh"], :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"]
FileTest.stubs(:exist?).returns true
end
it "should not ignore the report setting" do
@settings.setdefaults :section, :report => ["false", "a"]
myfile = stub "myfile"
@settings[:config] = myfile
text = <<-CONF
[puppetd]
report=true
CONF
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:report].should be_true
end
it "should use its current ':config' value for the file to parse" do
myfile = make_absolute("/my/file") # do not stub expand_path here, as this leads to a stack overflow, when mocha tries to use it
@settings[:config] = myfile
File.expects(:read).with(myfile).returns "[main]"
@settings.parse
end
it "should fail if no configuration setting is defined" do
@settings = Puppet::Util::Settings.new
lambda { @settings.parse }.should raise_error(RuntimeError)
end
it "should not try to parse non-existent files" do
FileTest.expects(:exist?).with("/some/file").returns false
File.expects(:read).with("/some/file").never
@settings.parse
end
it "should set a timer that triggers reparsing, even if the file does not exist" do
FileTest.expects(:exist?).returns false
@settings.expects(:set_filetimeout_timer)
@settings.parse
end
it "should return values set in the configuration file" do
text = "[main]
one = fileval
"
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:one].should == "fileval"
end
#484 - this should probably be in the regression area
it "should not throw an exception on unknown parameters" do
text = "[main]\nnosuchparam = mval\n"
@settings.expects(:read_file).returns(text)
lambda { @settings.parse }.should_not raise_error
end
it "should convert booleans in the configuration file into Ruby booleans" do
text = "[main]
one = true
two = false
"
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:one].should == true
@settings[:two].should == false
end
it "should convert integers in the configuration file into Ruby Integers" do
text = "[main]
one = 65
"
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:one].should == 65
end
it "should support specifying all metadata (owner, group, mode) in the configuration file" do
@settings.setdefaults :section, :myfile => ["/myfile", "a"]
otherfile = make_absolute("/other/file")
text = "[main]
myfile = #{otherfile} {owner = service, group = service, mode = 644}
"
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:myfile].should == otherfile
@settings.metadata(:myfile).should == {:owner => "suser", :group => "sgroup", :mode => "644"}
end
it "should support specifying a single piece of metadata (owner, group, or mode) in the configuration file" do
@settings.setdefaults :section, :myfile => ["/myfile", "a"]
otherfile = make_absolute("/other/file")
text = "[main]
myfile = #{otherfile} {owner = service}
"
file = "/some/file"
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:myfile].should == otherfile
@settings.metadata(:myfile).should == {:owner => "suser"}
end
it "should call hooks associated with values set in the configuration file" do
values = []
@settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }}
text = "[main]
mysetting = setval
"
@settings.expects(:read_file).returns(text)
@settings.parse
values.should == ["setval"]
end
it "should not call the same hook for values set multiple times in the configuration file" do
values = []
@settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }}
text = "[user]
mysetting = setval
[main]
mysetting = other
"
@settings.expects(:read_file).returns(text)
@settings.parse
values.should == ["setval"]
end
it "should pass the environment-specific value to the hook when one is available" do
values = []
@settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }}
@settings.setdefaults :section, :environment => ["yay", "a"]
@settings.setdefaults :section, :environments => ["yay,foo", "a"]
text = "[main]
mysetting = setval
[yay]
mysetting = other
"
@settings.expects(:read_file).returns(text)
@settings.parse
values.should == ["other"]
end
it "should pass the interpolated value to the hook when one is available" do
values = []
@settings.setdefaults :section, :base => {:default => "yay", :desc => "a", :hook => proc { |v| values << v }}
@settings.setdefaults :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }}
text = "[main]
mysetting = $base/setval
"
@settings.expects(:read_file).returns(text)
@settings.parse
values.should == ["yay/setval"]
end
it "should allow empty values" do
@settings.setdefaults :section, :myarg => ["myfile", "a"]
text = "[main]
myarg =
"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings[:myarg].should == ""
end
describe "and when reading a non-positive filetimeout value from the config file" do
before do
@settings.setdefaults :foo, :filetimeout => [5, "eh"]
somefile = "/some/file"
text = "[main]
filetimeout = -1
"
File.expects(:read).with(somefile).returns(text)
File.expects(:expand_path).with(somefile).returns somefile
@settings[:config] = somefile
end
it "should not set a timer" do
EventLoop::Timer.expects(:new).never
@settings.parse
end
end
end
describe "when reparsing its configuration" do
before do
@settings = Puppet::Util::Settings.new
@settings.setdefaults :section, :config => ["/test/file", "a"], :one => ["ONE", "a"], :two => ["$one TWO", "b"], :three => ["$one $two THREE", "c"]
FileTest.stubs(:exist?).returns true
end
it "should use a LoadedFile instance to determine if the file has changed" do
file = mock 'file'
Puppet::Util::LoadedFile.expects(:new).with("/test/file").returns file
file.expects(:changed?)
@settings.stubs(:parse)
@settings.reparse
end
it "should not create the LoadedFile instance and should not parse if the file does not exist" do
FileTest.expects(:exist?).with("/test/file").returns false
Puppet::Util::LoadedFile.expects(:new).never
@settings.expects(:parse).never
@settings.reparse
end
it "should not reparse if the file has not changed" do
file = mock 'file'
Puppet::Util::LoadedFile.expects(:new).with("/test/file").returns file
file.expects(:changed?).returns false
@settings.expects(:parse).never
@settings.reparse
end
it "should reparse if the file has changed" do
file = stub 'file', :file => "/test/file"
Puppet::Util::LoadedFile.expects(:new).with("/test/file").returns file
file.expects(:changed?).returns true
@settings.expects(:parse)
@settings.reparse
end
it "should replace in-memory values with on-file values" do
# Init the value
text = "[main]\none = disk-init\n"
file = mock 'file'
file.stubs(:changed?).returns(true)
file.stubs(:file).returns("/test/file")
@settings[:one] = "init"
@settings.file = file
# Now replace the value
text = "[main]\none = disk-replace\n"
# This is kinda ridiculous - the reason it parses twice is that
# it goes to parse again when we ask for the value, because the
# mock always says it should get reparsed.
@settings.stubs(:read_file).returns(text)
@settings.reparse
@settings[:one].should == "disk-replace"
end
it "should retain parameters set by cli when configuration files are reparsed" do
@settings.handlearg("--one", "clival")
text = "[main]\none = on-disk\n"
@settings.stubs(:read_file).returns(text)
@settings.parse
@settings[:one].should == "clival"
end
it "should remove in-memory values that are no longer set in the file" do
# Init the value
text = "[main]\none = disk-init\n"
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:one].should == "disk-init"
# Now replace the value
text = "[main]\ntwo = disk-replace\n"
@settings.expects(:read_file).returns(text)
@settings.parse
#@settings.reparse
# The originally-overridden value should be replaced with the default
@settings[:one].should == "ONE"
# and we should now have the new value in memory
@settings[:two].should == "disk-replace"
end
it "should retain in-memory values if the file has a syntax error" do
# Init the value
text = "[main]\none = initial-value\n"
@settings.expects(:read_file).returns(text)
@settings.parse
@settings[:one].should == "initial-value"
# Now replace the value with something bogus
text = "[main]\nkenny = killed-by-what-follows\n1 is 2, blah blah florp\n"
@settings.expects(:read_file).returns(text)
@settings.parse
# The originally-overridden value should not be replaced with the default
@settings[:one].should == "initial-value"
# and we should not have the new value in memory
@settings[:kenny].should be_nil
end
end
it "should provide a method for creating a catalog of resources from its configuration" do
Puppet::Util::Settings.new.should respond_to(:to_catalog)
end
describe "when creating a catalog" do
before do
@settings = Puppet::Util::Settings.new
@settings.stubs(:service_user_available?).returns true
@prefix = Puppet.features.posix? ? "" : "C:"
end
it "should add all file resources to the catalog if no sections have been specified" do
@settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"], :seconddir => [@prefix+"/seconddir", "a"]
@settings.setdefaults :other, :otherdir => [@prefix+"/otherdir", "a"]
catalog = @settings.to_catalog
[@prefix+"/maindir", @prefix+"/seconddir", @prefix+"/otherdir"].each do |path|
catalog.resource(:file, path).should be_instance_of(Puppet::Resource)
end
end
it "should add only files in the specified sections if section names are provided" do
@settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"]
@settings.setdefaults :other, :otherdir => [@prefix+"/otherdir", "a"]
catalog = @settings.to_catalog(:main)
catalog.resource(:file, @prefix+"/otherdir").should be_nil
catalog.resource(:file, @prefix+"/maindir").should be_instance_of(Puppet::Resource)
end
it "should not try to add the same file twice" do
@settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"]
@settings.setdefaults :other, :otherdir => [@prefix+"/maindir", "a"]
lambda { @settings.to_catalog }.should_not raise_error
end
it "should ignore files whose :to_resource method returns nil" do
@settings.setdefaults :main, :maindir => [@prefix+"/maindir", "a"]
@settings.setting(:maindir).expects(:to_resource).returns nil
Puppet::Resource::Catalog.any_instance.expects(:add_resource).never
@settings.to_catalog
end
describe "on Microsoft Windows" do
before :each do
Puppet.features.stubs(:root?).returns true
Puppet.features.stubs(:microsoft_windows?).returns true
@settings.setdefaults :foo, :mkusers => [true, "e"], :user => ["suser", "doc"], :group => ["sgroup", "doc"]
@settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "service", :group => "service"}
@catalog = @settings.to_catalog
end
it "it should not add users and groups to the catalog" do
@catalog.resource(:user, "suser").should be_nil
@catalog.resource(:group, "sgroup").should be_nil
end
end
describe "when adding users and groups to the catalog" do
before do
Puppet.features.stubs(:root?).returns true
Puppet.features.stubs(:microsoft_windows?).returns false
@settings.setdefaults :foo, :mkusers => [true, "e"], :user => ["suser", "doc"], :group => ["sgroup", "doc"]
@settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "service", :group => "service"}
@catalog = @settings.to_catalog
end
it "should add each specified user and group to the catalog if :mkusers is a valid setting, is enabled, and we're running as root" do
@catalog.resource(:user, "suser").should be_instance_of(Puppet::Resource)
@catalog.resource(:group, "sgroup").should be_instance_of(Puppet::Resource)
end
it "should only add users and groups to the catalog from specified sections" do
@settings.setdefaults :yay, :yaydir => {:default => "/yaydir", :desc => "a", :owner => "service", :group => "service"}
catalog = @settings.to_catalog(:other)
catalog.resource(:user, "jane").should be_nil
catalog.resource(:group, "billy").should be_nil
end
it "should not add users or groups to the catalog if :mkusers not running as root" do
Puppet.features.stubs(:root?).returns false
catalog = @settings.to_catalog
catalog.resource(:user, "suser").should be_nil
catalog.resource(:group, "sgroup").should be_nil
end
it "should not add users or groups to the catalog if :mkusers is not a valid setting" do
Puppet.features.stubs(:root?).returns true
settings = Puppet::Util::Settings.new
settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "service", :group => "service"}
catalog = settings.to_catalog
catalog.resource(:user, "suser").should be_nil
catalog.resource(:group, "sgroup").should be_nil
end
it "should not add users or groups to the catalog if :mkusers is a valid setting but is disabled" do
@settings[:mkusers] = false
catalog = @settings.to_catalog
catalog.resource(:user, "suser").should be_nil
catalog.resource(:group, "sgroup").should be_nil
end
it "should not try to add users or groups to the catalog twice" do
@settings.setdefaults :yay, :yaydir => {:default => "/yaydir", :desc => "a", :owner => "service", :group => "service"}
# This would fail if users/groups were added twice
lambda { @settings.to_catalog }.should_not raise_error
end
it "should set :ensure to :present on each created user and group" do
@catalog.resource(:user, "suser")[:ensure].should == :present
@catalog.resource(:group, "sgroup")[:ensure].should == :present
end
it "should set each created user's :gid to the service group" do
@settings.to_catalog.resource(:user, "suser")[:gid].should == "sgroup"
end
it "should not attempt to manage the root user" do
Puppet.features.stubs(:root?).returns true
@settings.setdefaults :foo, :foodir => {:default => "/foodir", :desc => "a", :owner => "root", :group => "service"}
@settings.to_catalog.resource(:user, "root").should be_nil
end
end
end
it "should be able to be converted to a manifest" do
Puppet::Util::Settings.new.should respond_to(:to_manifest)
end
describe "when being converted to a manifest" do
it "should produce a string with the code for each resource joined by two carriage returns" do
@settings = Puppet::Util::Settings.new
@settings.setdefaults :main, :maindir => ["/maindir", "a"], :seconddir => ["/seconddir", "a"]
main = stub 'main_resource', :ref => "File[/maindir]"
main.expects(:to_manifest).returns "maindir"
second = stub 'second_resource', :ref => "File[/seconddir]"
second.expects(:to_manifest).returns "seconddir"
@settings.setting(:maindir).expects(:to_resource).returns main
@settings.setting(:seconddir).expects(:to_resource).returns second
@settings.to_manifest.split("\n\n").sort.should == %w{maindir seconddir}
end
end
describe "when using sections of the configuration to manage the local host" do
before do
@settings = Puppet::Util::Settings.new
@settings.stubs(:service_user_available?).returns true
@settings.setdefaults :main, :noop => [false, ""]
@settings.setdefaults :main, :maindir => ["/maindir", "a"], :seconddir => ["/seconddir", "a"]
@settings.setdefaults :main, :user => ["suser", "doc"], :group => ["sgroup", "doc"]
@settings.setdefaults :other, :otherdir => {:default => "/otherdir", :desc => "a", :owner => "service", :group => "service", :mode => 0755}
@settings.setdefaults :third, :thirddir => ["/thirddir", "b"]
@settings.setdefaults :files, :myfile => {:default => "/myfile", :desc => "a", :mode => 0755}
end
it "should provide a method that writes files with the correct modes" do
@settings.should respond_to(:write)
end
it "should provide a method that creates directories with the correct modes" do
Puppet::Util::SUIDManager.expects(:asuser).with("suser", "sgroup").yields
Dir.expects(:mkdir).with("/otherdir", 0755)
@settings.mkdir(:otherdir)
end
it "should create a catalog with the specified sections" do
@settings.expects(:to_catalog).with(:main, :other).returns Puppet::Resource::Catalog.new("foo")
@settings.use(:main, :other)
end
it "should canonicalize the sections" do
@settings.expects(:to_catalog).with(:main, :other).returns Puppet::Resource::Catalog.new("foo")
@settings.use("main", "other")
end
it "should ignore sections that have already been used" do
@settings.expects(:to_catalog).with(:main).returns Puppet::Resource::Catalog.new("foo")
@settings.use(:main)
@settings.expects(:to_catalog).with(:other).returns Puppet::Resource::Catalog.new("foo")
@settings.use(:main, :other)
end
it "should ignore tags and schedules when creating files and directories"
it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" do
pending "Not converted from test/unit yet"
end
it "should convert the created catalog to a RAL catalog" do
@catalog = Puppet::Resource::Catalog.new("foo")
@settings.expects(:to_catalog).with(:main).returns @catalog
@catalog.expects(:to_ral).returns @catalog
@settings.use(:main)
end
it "should specify that it is not managing a host catalog" do
catalog = Puppet::Resource::Catalog.new("foo")
catalog.expects(:apply)
@settings.expects(:to_catalog).returns catalog
catalog.stubs(:to_ral).returns catalog
catalog.expects(:host_config=).with false
@settings.use(:main)
end
it "should support a method for re-using all currently used sections" do
@settings.expects(:to_catalog).with(:main, :third).times(2).returns Puppet::Resource::Catalog.new("foo")
@settings.use(:main, :third)
@settings.reuse
end
it "should fail with an appropriate message if any resources fail" do
@catalog = Puppet::Resource::Catalog.new("foo")
@catalog.stubs(:to_ral).returns @catalog
@settings.expects(:to_catalog).returns @catalog
@trans = mock("transaction")
@catalog.expects(:apply).yields(@trans)
@trans.expects(:any_failed?).returns(true)
report = mock 'report'
@trans.expects(:report).returns report
log = mock 'log', :to_s => "My failure", :level => :err
report.expects(:logs).returns [log]
@settings.expects(:raise).with { |msg| msg.include?("My failure") }
@settings.use(:whatever)
end
end
describe "when dealing with printing configs" do
before do
@settings = Puppet::Util::Settings.new
#these are the magic default values
@settings.stubs(:value).with(:configprint).returns("")
@settings.stubs(:value).with(:genconfig).returns(false)
@settings.stubs(:value).with(:genmanifest).returns(false)
@settings.stubs(:value).with(:environment).returns(nil)
end
describe "when checking print_config?" do
it "should return false when the :configprint, :genconfig and :genmanifest are not set" do
@settings.print_configs?.should be_false
end
it "should return true when :configprint has a value" do
@settings.stubs(:value).with(:configprint).returns("something")
@settings.print_configs?.should be_true
end
it "should return true when :genconfig has a value" do
@settings.stubs(:value).with(:genconfig).returns(true)
@settings.print_configs?.should be_true
end
it "should return true when :genmanifest has a value" do
@settings.stubs(:value).with(:genmanifest).returns(true)
@settings.print_configs?.should be_true
end
end
describe "when printing configs" do
describe "when :configprint has a value" do
it "should call print_config_options" do
@settings.stubs(:value).with(:configprint).returns("something")
@settings.expects(:print_config_options)
@settings.print_configs
end
it "should get the value of the option using the environment" do
@settings.stubs(:value).with(:configprint).returns("something")
@settings.stubs(:include?).with("something").returns(true)
@settings.expects(:value).with(:environment).returns("env")
@settings.expects(:value).with("something", "env").returns("foo")
@settings.stubs(:puts).with("foo")
@settings.print_configs
end
it "should print the value of the option" do
@settings.stubs(:value).with(:configprint).returns("something")
@settings.stubs(:include?).with("something").returns(true)
@settings.stubs(:value).with("something", nil).returns("foo")
@settings.expects(:puts).with("foo")
@settings.print_configs
end
it "should print the value pairs if there are multiple options" do
@settings.stubs(:value).with(:configprint).returns("bar,baz")
@settings.stubs(:include?).with("bar").returns(true)
@settings.stubs(:include?).with("baz").returns(true)
@settings.stubs(:value).with("bar", nil).returns("foo")
@settings.stubs(:value).with("baz", nil).returns("fud")
@settings.expects(:puts).with("bar = foo")
@settings.expects(:puts).with("baz = fud")
@settings.print_configs
end
it "should print a whole bunch of stuff if :configprint = all"
it "should return true after printing" do
@settings.stubs(:value).with(:configprint).returns("something")
@settings.stubs(:include?).with("something").returns(true)
@settings.stubs(:value).with("something", nil).returns("foo")
@settings.stubs(:puts).with("foo")
@settings.print_configs.should be_true
end
it "should return false if a config param is not found" do
@settings.stubs :puts
@settings.stubs(:value).with(:configprint).returns("something")
@settings.stubs(:include?).with("something").returns(false)
@settings.print_configs.should be_false
end
end
describe "when genconfig is true" do
before do
@settings.stubs :puts
end
it "should call to_config" do
@settings.stubs(:value).with(:genconfig).returns(true)
@settings.expects(:to_config)
@settings.print_configs
end
it "should return true from print_configs" do
@settings.stubs(:value).with(:genconfig).returns(true)
@settings.stubs(:to_config)
@settings.print_configs.should be_true
end
end
describe "when genmanifest is true" do
before do
@settings.stubs :puts
end
it "should call to_config" do
@settings.stubs(:value).with(:genmanifest).returns(true)
@settings.expects(:to_manifest)
@settings.print_configs
end
it "should return true from print_configs" do
@settings.stubs(:value).with(:genmanifest).returns(true)
@settings.stubs(:to_manifest)
@settings.print_configs.should be_true
end
end
end
end
describe "when setting a timer to trigger configuration file reparsing" do
before do
@settings = Puppet::Util::Settings.new
@settings.setdefaults :foo, :filetimeout => [5, "eh"]
end
it "should do nothing if no filetimeout setting is available" do
@settings.expects(:value).with(:filetimeout).returns nil
EventLoop::Timer.expects(:new).never
@settings.set_filetimeout_timer
end
it "should always convert the timer interval to an integer" do
@settings.expects(:value).with(:filetimeout).returns "10"
EventLoop::Timer.expects(:new).with(:interval => 10, :start? => true, :tolerance => 1)
@settings.set_filetimeout_timer
end
it "should do nothing if the filetimeout setting is not greater than 0" do
@settings.expects(:value).with(:filetimeout).returns -2
EventLoop::Timer.expects(:new).never
@settings.set_filetimeout_timer
end
it "should create a timer with its interval set to the filetimeout, start? set to true, and a tolerance of 1" do
@settings.expects(:value).with(:filetimeout).returns 5
EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1)
@settings.set_filetimeout_timer
end
it "should reparse when the timer goes off" do
EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1).yields
@settings.expects(:reparse)
@settings.set_filetimeout_timer
end
end
describe "when determining if the service user is available" do
it "should return false if there is no user setting" do
Puppet::Util::Settings.new.should_not be_service_user_available
end
it "should return false if the user provider says the user is missing" do
settings = Puppet::Util::Settings.new
settings.setdefaults :main, :user => ["foo", "doc"]
user = mock 'user'
user.expects(:exists?).returns false
Puppet::Type.type(:user).expects(:new).with { |args| args[:name] == "foo" }.returns user
settings.should_not be_service_user_available
end
it "should return true if the user provider says the user is present" do
settings = Puppet::Util::Settings.new
settings.setdefaults :main, :user => ["foo", "doc"]
user = mock 'user'
user.expects(:exists?).returns true
Puppet::Type.type(:user).expects(:new).with { |args| args[:name] == "foo" }.returns user
settings.should be_service_user_available
end
it "should cache the result"
end
describe "#writesub" do
it "should only pass valid arguments to File.open" do
settings = Puppet::Util::Settings.new
settings.stubs(:get_config_file_default).with(:privatekeydir).returns(OpenStruct.new(:mode => "750"))
File.expects(:open).with("/path/to/keydir", "w", 750).returns true
settings.writesub(:privatekeydir, "/path/to/keydir")
end
end
end
diff --git a/spec/unit/util_spec.rb b/spec/unit/util_spec.rb
index 8ac8017d9..4c57ee8b1 100755
--- a/spec/unit/util_spec.rb
+++ b/spec/unit/util_spec.rb
@@ -1,537 +1,546 @@
#!/usr/bin/env ruby
require 'spec_helper'
describe Puppet::Util do
def process_status(exitstatus)
return exitstatus if Puppet.features.microsoft_windows?
stub('child_status', :exitstatus => exitstatus)
end
describe "#absolute_path?" do
it "should default to the platform of the local system" do
Puppet.features.stubs(:posix?).returns(true)
Puppet.features.stubs(:microsoft_windows?).returns(false)
Puppet::Util.should be_absolute_path('/foo')
Puppet::Util.should_not be_absolute_path('C:/foo')
Puppet.features.stubs(:posix?).returns(false)
Puppet.features.stubs(:microsoft_windows?).returns(true)
Puppet::Util.should be_absolute_path('C:/foo')
Puppet::Util.should_not be_absolute_path('/foo')
end
describe "when using platform :posix" do
%w[/ /foo /foo/../bar //foo //Server/Foo/Bar //?/C:/foo/bar /\Server/Foo /foo//bar/baz].each do |path|
it "should return true for #{path}" do
Puppet::Util.should be_absolute_path(path, :posix)
end
end
%w[. ./foo \foo C:/foo \\Server\Foo\Bar \\?\C:\foo\bar \/?/foo\bar \/Server/foo foo//bar/baz].each do |path|
it "should return false for #{path}" do
Puppet::Util.should_not be_absolute_path(path, :posix)
end
end
end
describe "when using platform :windows" do
%w[C:/foo C:\foo \\\\Server\Foo\Bar \\\\?\C:\foo\bar //Server/Foo/Bar //?/C:/foo/bar /\?\C:/foo\bar \/Server\Foo/Bar c:/foo//bar//baz].each do |path|
it "should return true for #{path}" do
Puppet::Util.should be_absolute_path(path, :windows)
end
end
%w[/ . ./foo \foo /foo /foo/../bar //foo C:foo/bar foo//bar/baz].each do |path|
it "should return false for #{path}" do
Puppet::Util.should_not be_absolute_path(path, :windows)
end
end
end
end
describe "#path_to_uri" do
%w[. .. foo foo/bar foo/../bar].each do |path|
it "should reject relative path: #{path}" do
lambda { Puppet::Util.path_to_uri(path) }.should raise_error(Puppet::Error)
end
end
it "should perform URI escaping" do
Puppet::Util.path_to_uri("/foo bar").path.should == "/foo%20bar"
end
describe "when using platform :posix" do
before :each do
Puppet.features.stubs(:posix).returns true
Puppet.features.stubs(:microsoft_windows?).returns false
end
%w[/ /foo /foo/../bar].each do |path|
it "should convert #{path} to URI" do
Puppet::Util.path_to_uri(path).path.should == path
end
end
end
describe "when using platform :windows" do
before :each do
Puppet.features.stubs(:posix).returns false
Puppet.features.stubs(:microsoft_windows?).returns true
end
it "should normalize backslashes" do
Puppet::Util.path_to_uri('c:\\foo\\bar\\baz').path.should == '/' + 'c:/foo/bar/baz'
end
%w[C:/ C:/foo/bar].each do |path|
it "should convert #{path} to absolute URI" do
Puppet::Util.path_to_uri(path).path.should == '/' + path
end
end
%w[share C$].each do |path|
it "should convert UNC #{path} to absolute URI" do
uri = Puppet::Util.path_to_uri("\\\\server\\#{path}")
uri.host.should == 'server'
uri.path.should == '/' + path
end
end
end
end
describe ".uri_to_path" do
require 'uri'
it "should strip host component" do
Puppet::Util.uri_to_path(URI.parse('http://foo/bar')).should == '/bar'
end
it "should accept puppet URLs" do
Puppet::Util.uri_to_path(URI.parse('puppet:///modules/foo')).should == '/modules/foo'
end
it "should return unencoded path" do
Puppet::Util.uri_to_path(URI.parse('http://foo/bar%20baz')).should == '/bar baz'
end
it "should be nil-safe" do
Puppet::Util.uri_to_path(nil).should be_nil
end
describe "when using platform :posix",:if => Puppet.features.posix? do
it "should accept root" do
Puppet::Util.uri_to_path(URI.parse('file:/')).should == '/'
end
it "should accept single slash" do
Puppet::Util.uri_to_path(URI.parse('file:/foo/bar')).should == '/foo/bar'
end
it "should accept triple slashes" do
Puppet::Util.uri_to_path(URI.parse('file:///foo/bar')).should == '/foo/bar'
end
end
describe "when using platform :windows", :if => Puppet.features.microsoft_windows? do
it "should accept root" do
Puppet::Util.uri_to_path(URI.parse('file:/C:/')).should == 'C:/'
end
it "should accept single slash" do
Puppet::Util.uri_to_path(URI.parse('file:/C:/foo/bar')).should == 'C:/foo/bar'
end
it "should accept triple slashes" do
Puppet::Util.uri_to_path(URI.parse('file:///C:/foo/bar')).should == 'C:/foo/bar'
end
it "should accept file scheme with double slashes as a UNC path" do
Puppet::Util.uri_to_path(URI.parse('file://host/share/file')).should == '//host/share/file'
end
end
end
describe "execution methods" do
let(:pid) { 5501 }
let(:null_file) { Puppet.features.microsoft_windows? ? 'NUL' : '/dev/null' }
describe "#execute_posix" do
before :each do
# Most of the things this method does are bad to do during specs. :/
Kernel.stubs(:fork).returns(pid).yields
Process.stubs(:setsid)
Kernel.stubs(:exec)
Puppet::Util::SUIDManager.stubs(:change_user)
Puppet::Util::SUIDManager.stubs(:change_group)
$stdin.stubs(:reopen)
$stdout.stubs(:reopen)
$stderr.stubs(:reopen)
@stdin = File.open(null_file, 'r')
@stdout = Tempfile.new('stdout')
@stderr = File.open(null_file, 'w')
end
it "should fork a child process to execute the command" do
Kernel.expects(:fork).returns(pid).yields
Kernel.expects(:exec).with('test command')
Puppet::Util.execute_posix('test command', {}, @stdin, @stdout, @stderr)
end
it "should start a new session group" do
Process.expects(:setsid)
Puppet::Util.execute_posix('test command', {}, @stdin, @stdout, @stderr)
end
it "should close all open file descriptors except stdin/stdout/stderr" do
# This is ugly, but I can't really think of a better way to do it without
# letting it actually close fds, which seems risky
(0..2).each {|n| IO.expects(:new).with(n).never}
(3..256).each {|n| IO.expects(:new).with(n).returns mock('io', :close) }
Puppet::Util.execute_posix('test command', {}, @stdin, @stdout, @stderr)
end
it "should permanently change to the correct user and group if specified" do
Puppet::Util::SUIDManager.expects(:change_group).with(55, true)
Puppet::Util::SUIDManager.expects(:change_user).with(50, true)
Puppet::Util.execute_posix('test command', {:uid => 50, :gid => 55}, @stdin, @stdout, @stderr)
end
it "should exit failure if there is a problem execing the command" do
Kernel.expects(:exec).with('test command').raises("failed to execute!")
Puppet::Util.stubs(:puts)
Puppet::Util.expects(:exit!).with(1)
Puppet::Util.execute_posix('test command', {}, @stdin, @stdout, @stderr)
end
it "should properly execute commands specified as arrays" do
Kernel.expects(:exec).with('test command', 'with', 'arguments')
Puppet::Util.execute_posix(['test command', 'with', 'arguments'], {:uid => 50, :gid => 55}, @stdin, @stdout, @stderr)
end
+ it "should properly execute string commands with embedded newlines" do
+ Kernel.expects(:exec).with("/bin/echo 'foo' ; \n /bin/echo 'bar' ;")
+
+ Puppet::Util.execute_posix("/bin/echo 'foo' ; \n /bin/echo 'bar' ;", {:uid => 50, :gid => 55}, @stdin, @stdout, @stderr)
+ end
+
it "should return the pid of the child process" do
Puppet::Util.execute_posix('test command', {}, @stdin, @stdout, @stderr).should == pid
end
end
describe "#execute_windows" do
let(:proc_info_stub) { stub 'processinfo', :process_id => pid }
before :each do
Process.stubs(:create).returns(proc_info_stub)
Process.stubs(:waitpid2).with(pid).returns([pid, process_status(0)])
@stdin = File.open(null_file, 'r')
@stdout = Tempfile.new('stdout')
@stderr = File.open(null_file, 'w')
end
it "should create a new process for the command" do
Process.expects(:create).with(
:command_line => "test command",
:startup_info => {:stdin => @stdin, :stdout => @stdout, :stderr => @stderr}
).returns(proc_info_stub)
Puppet::Util.execute_windows('test command', {}, @stdin, @stdout, @stderr)
end
it "should return the pid of the child process" do
Puppet::Util.execute_windows('test command', {}, @stdin, @stdout, @stderr).should == pid
end
it "should quote arguments containing spaces if command is specified as an array" do
Process.expects(:create).with do |args|
args[:command_line] == '"test command" with some "arguments \"with spaces"'
end.returns(proc_info_stub)
Puppet::Util.execute_windows(['test command', 'with', 'some', 'arguments "with spaces'], {}, @stdin, @stdout, @stderr)
end
end
describe "#execute" do
before :each do
Process.stubs(:waitpid2).with(pid).returns([pid, process_status(0)])
end
describe "when an execution stub is specified" do
before :each do
Puppet::Util::ExecutionStub.set do |command,args,stdin,stdout,stderr|
"execution stub output"
end
end
it "should call the block on the stub" do
Puppet::Util.execute("/usr/bin/run_my_execute_stub").should == "execution stub output"
end
it "should not actually execute anything" do
Puppet::Util.expects(:execute_posix).never
Puppet::Util.expects(:execute_windows).never
Puppet::Util.execute("/usr/bin/run_my_execute_stub")
end
end
describe "when setting up input and output files" do
include PuppetSpec::Files
let(:executor) { Puppet.features.microsoft_windows? ? 'execute_windows' : 'execute_posix' }
before :each do
Puppet::Util.stubs(:wait_for_output)
end
it "should set stdin to the stdinfile if specified" do
input = tmpfile('stdin')
FileUtils.touch(input)
Puppet::Util.expects(executor).with do |_,_,stdin,_,_|
stdin.path == input
end.returns(pid)
Puppet::Util.execute('test command', :stdinfile => input)
end
it "should set stdin to the null file if not specified" do
Puppet::Util.expects(executor).with do |_,_,stdin,_,_|
stdin.path == null_file
end.returns(pid)
Puppet::Util.execute('test command')
end
describe "when squelch is set" do
it "should set stdout and stderr to the null file" do
Puppet::Util.expects(executor).with do |_,_,_,stdout,stderr|
stdout.path == null_file and stderr.path == null_file
end.returns(pid)
Puppet::Util.execute('test command', :squelch => true)
end
end
describe "when squelch is not set" do
it "should set stdout to a temporary output file" do
outfile = Tempfile.new('stdout')
Tempfile.stubs(:new).returns(outfile)
Puppet::Util.expects(executor).with do |_,_,_,stdout,_|
stdout.path == outfile.path
end.returns(pid)
Puppet::Util.execute('test command', :squelch => false)
end
it "should set stderr to the same file as stdout if combine is true" do
outfile = Tempfile.new('stdout')
Tempfile.stubs(:new).returns(outfile)
Puppet::Util.expects(executor).with do |_,_,_,stdout,stderr|
stdout.path == outfile.path and stderr.path == outfile.path
end.returns(pid)
Puppet::Util.execute('test command', :squelch => false, :combine => true)
end
it "should set stderr to the null device if combine is false" do
outfile = Tempfile.new('stdout')
Tempfile.stubs(:new).returns(outfile)
Puppet::Util.expects(executor).with do |_,_,_,stdout,stderr|
stdout.path == outfile.path and stderr.path == null_file
end.returns(pid)
Puppet::Util.execute('test command', :squelch => false, :combine => false)
end
end
end
end
describe "after execution" do
let(:executor) { Puppet.features.microsoft_windows? ? 'execute_windows' : 'execute_posix' }
before :each do
Process.stubs(:waitpid2).with(pid).returns([pid, process_status(0)])
Puppet::Util.stubs(executor).returns(pid)
end
it "should wait for the child process to exit" do
Puppet::Util.stubs(:wait_for_output)
Process.expects(:waitpid2).with(pid).returns([pid, process_status(0)])
Puppet::Util.execute('test command')
end
it "should close the stdin/stdout/stderr files used by the child" do
stdin = mock 'file', :close
stdout = mock 'file', :close
stderr = mock 'file', :close
File.expects(:open).
times(3).
returns(stdin).
then.returns(stdout).
then.returns(stderr)
Puppet::Util.execute('test command', :squelch => true)
end
it "should read and return the output if squelch is false" do
stdout = Tempfile.new('test')
Tempfile.stubs(:new).returns(stdout)
stdout.write("My expected command output")
Puppet::Util.execute('test command').should == "My expected command output"
end
it "should not read the output if squelch is true" do
stdout = Tempfile.new('test')
Tempfile.stubs(:new).returns(stdout)
stdout.write("My expected command output")
Puppet::Util.execute('test command', :squelch => true).should == nil
end
it "should delete the file used for output if squelch is false" do
stdout = Tempfile.new('test')
path = stdout.path
Tempfile.stubs(:new).returns(stdout)
Puppet::Util.execute('test command')
File.should_not be_exist(path)
end
it "should raise an error if failonfail is true and the child failed" do
Process.expects(:waitpid2).with(pid).returns([pid, process_status(1)])
expect {
Puppet::Util.execute('fail command', :failonfail => true)
}.to raise_error(Puppet::ExecutionFailure, /Execution of 'fail command' returned 1/)
end
it "should not raise an error if failonfail is false and the child failed" do
Process.expects(:waitpid2).with(pid).returns([pid, process_status(1)])
expect {
Puppet::Util.execute('fail command', :failonfail => false)
}.not_to raise_error
end
it "should not raise an error if failonfail is true and the child succeeded" do
Process.expects(:waitpid2).with(pid).returns([pid, process_status(0)])
expect {
Puppet::Util.execute('fail command', :failonfail => true)
}.not_to raise_error
end
end
end
describe "#which" do
let(:base) { File.expand_path('/bin') }
let(:path) { File.join(base, 'foo') }
before :each do
FileTest.stubs(:file?).returns false
FileTest.stubs(:file?).with(path).returns true
FileTest.stubs(:executable?).returns false
FileTest.stubs(:executable?).with(path).returns true
end
it "should accept absolute paths" do
Puppet::Util.which(path).should == path
end
it "should return nil if no executable found" do
Puppet::Util.which('doesnotexist').should be_nil
end
it "should reject directories" do
Puppet::Util.which(base).should be_nil
end
describe "on POSIX systems" do
before :each do
Puppet.features.stubs(:posix?).returns true
Puppet.features.stubs(:microsoft_windows?).returns false
end
it "should walk the search PATH returning the first executable" do
ENV.stubs(:[]).with('PATH').returns(File.expand_path('/bin'))
Puppet::Util.which('foo').should == path
end
end
describe "on Windows systems" do
let(:path) { File.expand_path(File.join(base, 'foo.CMD')) }
before :each do
Puppet.features.stubs(:posix?).returns false
Puppet.features.stubs(:microsoft_windows?).returns true
end
describe "when a file extension is specified" do
it "should walk each directory in PATH ignoring PATHEXT" do
ENV.stubs(:[]).with('PATH').returns(%w[/bar /bin].map{|dir| File.expand_path(dir)}.join(File::PATH_SEPARATOR))
FileTest.expects(:file?).with(File.join(File.expand_path('/bar'), 'foo.CMD')).returns false
ENV.expects(:[]).with('PATHEXT').never
Puppet::Util.which('foo.CMD').should == path
end
end
describe "when a file extension is not specified" do
it "should walk each extension in PATHEXT until an executable is found" do
- ENV.stubs(:[]).with('PATH').returns(base)
+ bar = File.expand_path('/bar')
+ ENV.stubs(:[]).with('PATH').returns("#{bar}#{File::PATH_SEPARATOR}#{base}")
ENV.stubs(:[]).with('PATHEXT').returns(".EXE#{File::PATH_SEPARATOR}.CMD")
exts = sequence('extensions')
+ FileTest.expects(:file?).in_sequence(exts).with(File.join(bar, 'foo.EXE')).returns false
+ FileTest.expects(:file?).in_sequence(exts).with(File.join(bar, 'foo.CMD')).returns false
FileTest.expects(:file?).in_sequence(exts).with(File.join(base, 'foo.EXE')).returns false
FileTest.expects(:file?).in_sequence(exts).with(path).returns true
Puppet::Util.which('foo').should == path
end
it "should walk the default extension path if the environment variable is not defined" do
ENV.stubs(:[]).with('PATH').returns(base)
ENV.stubs(:[]).with('PATHEXT').returns(nil)
exts = sequence('extensions')
%w[.COM .EXE .BAT].each do |ext|
FileTest.expects(:file?).in_sequence(exts).with(File.join(base, "foo#{ext}")).returns false
end
FileTest.expects(:file?).in_sequence(exts).with(path).returns true
Puppet::Util.which('foo').should == path
end
it "should fall back if no extension matches" do
ENV.stubs(:[]).with('PATH').returns(base)
ENV.stubs(:[]).with('PATHEXT').returns(".EXE")
FileTest.stubs(:file?).with(File.join(base, 'foo.EXE')).returns false
FileTest.stubs(:file?).with(File.join(base, 'foo')).returns true
FileTest.stubs(:executable?).with(File.join(base, 'foo')).returns true
Puppet::Util.which('foo').should == File.join(base, 'foo')
end
end
end
end
end
diff --git a/test/certmgr/certmgr.rb b/test/certmgr/certmgr.rb
deleted file mode 100755
index 11ecd6307..000000000
--- a/test/certmgr/certmgr.rb
+++ /dev/null
@@ -1,308 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
-
-require 'puppet'
-require 'puppet/sslcertificates.rb'
-require 'puppettest'
-require 'puppettest/certificates'
-require 'mocha'
-
-class TestCertMgr < Test::Unit::TestCase
- include PuppetTest::Certificates
- def setup
- super
- #@dir = File.join(Puppet[:certdir], "testing")
- @dir = File.join(@configpath, "certest")
- system("mkdir -p #{@dir}")
-
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- end
-
- def testCreateSelfSignedCertificate
- cert = nil
- name = "testing"
- newcert = proc {
-
- Puppet::SSLCertificates::Certificate.new(
-
- :name => name,
-
- :selfsign => true
- )
- }
- assert_nothing_raised {
- cert = newcert.call
- }
- assert_nothing_raised {
- cert.mkselfsigned
- }
-
- assert_raise(Puppet::Error) {
- cert.mkselfsigned
- }
-
- assert_nothing_raised {
- cert.write
- }
-
- assert(FileTest.exists?(cert.certfile))
-
- assert_nothing_raised {
- cert.delete
- }
-
- assert_nothing_raised {
- cert = newcert.call
- }
- assert_nothing_raised {
- cert.mkselfsigned
- }
-
- assert_nothing_raised {
- cert.delete
- }
-
- end
-
- def disabled_testCreateEncryptedSelfSignedCertificate
- cert = nil
- name = "testing"
- keyfile = mkPassFile
- assert_nothing_raised {
-
- cert = Puppet::SSLCertificates::Certificate.new(
-
- :name => name,
- :selfsign => true,
-
- :capass => keyfile
- )
- }
- assert_nothing_raised {
- cert.mkselfsigned
- }
- assert_nothing_raised {
- cert.mkhash
- }
-
- assert_raise(Puppet::Error) {
- cert.mkselfsigned
- }
-
- assert(FileTest.exists?(cert.certfile))
- assert(FileTest.exists?(cert.hash))
-
- assert_nothing_raised {
- cert.delete
- }
-
- assert_nothing_raised {
- cert.mkselfsigned
- }
-
- assert_nothing_raised {
- cert.delete
- }
-
- end
-
- def testCreateCA
- ca = nil
- assert_nothing_raised {
- ca = Puppet::SSLCertificates::CA.new
- }
-
- # make the CA again and verify it doesn't fail because everything
- # still exists
- assert_nothing_raised {
- ca = Puppet::SSLCertificates::CA.new
- }
-
- end
-
- def testSignCert
- ca = mkCA()
-
- cert = nil
- assert_nothing_raised {
-
- cert = Puppet::SSLCertificates::Certificate.new(
-
- :name => "signedcertest",
- :property => "TN",
- :city => "Nashville",
- :country => "US",
- :email => "luke@madstop.com",
- :org => "Puppet",
- :ou => "Development",
-
- :encrypt => mkPassFile()
- )
-
- }
-
- assert_nothing_raised {
- cert.mkcsr
- }
-
- signedcert = nil
- cacert = nil
-
- assert_nothing_raised {
- signedcert, cacert = ca.sign(cert.csr)
- }
-
- assert_instance_of(OpenSSL::X509::Certificate, signedcert)
- assert_instance_of(OpenSSL::X509::Certificate, cacert)
-
- assert_nothing_raised {
- cert.cert = signedcert
- cert.cacert = cacert
- cert.write
- }
- #system("find #{Puppet[:ssldir]}")
- #system("cp -R #{Puppet[:ssldir]} /tmp/ssltesting")
-
- output = nil
- assert_nothing_raised {
- output = %x{openssl verify -CAfile #{Puppet[:cacert]} -purpose sslserver #{cert.certfile}}
- #output = %x{openssl verify -CApath #{Puppet[:certdir]} -purpose sslserver #{cert.certfile}}
- }
-
- assert_equal($CHILD_STATUS,0)
- assert_equal(File.join(Puppet[:certdir], "signedcertest.pem: OK\n"), output)
- end
-
-
- def test_interactiveca
- ca = nil
-
- assert_nothing_raised {
- ca = Puppet::SSLCertificates::CA.new
- }
-
- # basic initialization
- hostname = "test.hostname.com"
- cert = mkcert(hostname)
-
- # create the csr
- csr = nil
- assert_nothing_raised {
- csr = cert.mkcsr
- }
-
- assert_nothing_raised {
- ca.storeclientcsr(csr)
- }
-
- # store it
- pulledcsr = nil
- assert_nothing_raised {
- pulledcsr = ca.getclientcsr(hostname)
- }
-
- assert_equal(csr.to_pem, pulledcsr.to_pem)
-
- signedcert = nil
- assert_nothing_raised {
- signedcert, cacert = ca.sign(csr)
- }
-
- assert_instance_of(OpenSSL::X509::Certificate, signedcert)
- newsignedcert = nil
- assert_nothing_raised {
- newsignedcert, cacert = ca.getclientcert(hostname)
- }
-
- assert(newsignedcert)
-
- assert_equal(signedcert.to_pem, newsignedcert.to_pem)
- end
-
- def test_cafailures
- ca = mkCA()
- cert = cacert = nil
- assert_nothing_raised {
- cert, cacert = ca.getclientcert("nohost")
- }
- assert_nil(cert)
- end
-
- def test_crl
- ca = mkCA()
- h1 = mksignedcert(ca, "host1.example.com")
- h2 = mksignedcert(ca, "host2.example.com")
-
- assert(ca.cert.verify(ca.cert.public_key))
- assert(h1.verify(ca.cert.public_key))
- assert(h2.verify(ca.cert.public_key))
-
- crl = ca.crl
- assert_not_nil(crl)
-
- store = mkStore(ca)
- assert( store.verify(ca.cert))
- assert( store.verify(h1, [ca.cert]))
- assert( store.verify(h2, [ca.cert]))
-
- ca.revoke(h1.serial)
-
- oldcert = File.read(Puppet.settings[:cacert])
- oldserial = File.read(Puppet.settings[:serial])
-
- # Recreate the CA from disk
- ca = mkCA()
- newcert = File.read(Puppet.settings[:cacert])
- newserial = File.read(Puppet.settings[:serial])
- assert_equal(oldcert, newcert, "The certs are not equal after making a new CA.")
- assert_equal(oldserial, newserial, "The serials are not equal after making a new CA.")
- store = mkStore(ca)
- assert( store.verify(ca.cert), "Could not verify CA certs after reloading certs.")
- assert(!store.verify(h1, [ca.cert]), "Incorrectly verified revoked cert.")
- assert( store.verify(h2, [ca.cert]), "Could not verify certs with reloaded CA.")
-
- ca.revoke(h2.serial)
- assert_equal(1, ca.crl.extensions.size)
-
- # Recreate the CA from disk
- ca = mkCA()
- store = mkStore(ca)
- assert( store.verify(ca.cert))
- assert(!store.verify(h1, [ca.cert]), "first revoked cert passed")
- assert(!store.verify(h2, [ca.cert]), "second revoked cert passed")
- end
-
- def test_ttl
- cert = mksignedcert
- assert_equal(5 * 365 * 24 * 60 * 60, cert.not_after - cert.not_before)
-
- Puppet[:ca_ttl] = 7 * 24 * 60 * 60
- cert = mksignedcert
- assert_equal(7 * 24 * 60 * 60, cert.not_after - cert.not_before)
-
- Puppet[:ca_ttl] = "2y"
- cert = mksignedcert
- assert_equal(2 * 365 * 24 * 60 * 60, cert.not_after - cert.not_before)
-
- Puppet[:ca_ttl] = "2y"
- cert = mksignedcert
- assert_equal(2 * 365 * 24 * 60 * 60, cert.not_after - cert.not_before)
-
- Puppet[:ca_ttl] = "1h"
- cert = mksignedcert
- assert_equal(60 * 60, cert.not_after - cert.not_before)
-
- Puppet[:ca_ttl] = "900s"
- cert = mksignedcert
- assert_equal(900, cert.not_after - cert.not_before)
-
- # This needs to be last, to make sure that setting ca_days
- # overrides setting ca_ttl
- Puppet[:ca_days] = 3
- cert = mksignedcert
- assert_equal(3 * 24 * 60 * 60, cert.not_after - cert.not_before)
-
- end
-end
-
diff --git a/test/certmgr/inventory.rb b/test/certmgr/inventory.rb
deleted file mode 100755
index fa612b2c1..000000000
--- a/test/certmgr/inventory.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
-
-require 'puppet'
-require 'puppettest/certificates'
-require 'puppet/sslcertificates/inventory.rb'
-require 'mocha'
-
-class TestCertInventory < Test::Unit::TestCase
- include PuppetTest::Certificates
-
- Inventory = Puppet::SSLCertificates::Inventory
-
- def setup
- super
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- end
-
- def test_format
- cert = mksignedcert
-
- format = nil
- assert_nothing_raised do
- format = Inventory.format(cert)
- end
-
-
- assert(
- format =~ /^0x0001 \S+ \S+ #{cert.subject}/,
-
- "Did not create correct format")
- end
-
- def test_init
- # First create a couple of certificates
- ca = mkCA
-
- cert1 = mksignedcert(ca, "host1.madstop.com")
- cert2 = mksignedcert(ca, "host2.madstop.com")
-
- init = nil
- assert_nothing_raised do
- init = Inventory.init
- end
-
- [cert1, cert2].each do |cert|
- assert(init.include?(cert.subject.to_s), "Did not catch #{cert.subject}")
- end
- end
-
- def test_add
- ca = mkCA
- cert = mksignedcert(ca, "host.domain.com")
-
- assert_nothing_raised do
- file = mock
- file.expects(:puts).with do |written|
- written.include? cert.subject.to_s
- end
- Puppet::Util::Settings.any_instance.stubs(:write)
- Puppet::Util::Settings.any_instance.expects(:write).
- with(:cert_inventory, 'a').yields(file)
-
- Puppet::SSLCertificates::Inventory.add(cert)
- end
- end
-end
-
diff --git a/test/certmgr/support.rb b/test/certmgr/support.rb
deleted file mode 100755
index f85d54a8a..000000000
--- a/test/certmgr/support.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/sslcertificates/support'
-require 'mocha'
-
-class TestCertSupport < Test::Unit::TestCase
- include PuppetTest
- MissingCertificate = Puppet::SSLCertificates::Support::MissingCertificate
-
- class CertUser
- include Puppet::SSLCertificates::Support
- end
-
- def setup
- super
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- @user = CertUser.new
- @ca = Puppet::SSLCertificates::CA.new
- @client = Puppet::Network::Client.ca.new(:CA => @ca)
- end
-
- # Yay, metaprogramming
- def test_keytype
- [:key, :csr, :cert, :ca_cert].each do |name|
- assert(Puppet::SSLCertificates::Support.method_defined?(name), "No retrieval method for #{name}")
- maker = "mk_#{name}"
- assert(Puppet::SSLCertificates::Support.method_defined?(maker), "No maker method for #{name}")
- end
- end
-
- def test_keys
- keys = [:hostprivkey, :hostpubkey].each { |n| Puppet[n] = tempfile }
-
- key = nil
- assert_nothing_raised do
- key = @user.key
- end
-
- assert_logged(:info, /Creating a new SSL/, "Did not log about new key")
- keys.each do |file|
-
- assert(
- FileTest.exists?(Puppet[file]),
-
- "Did not create #{file} key file")
- end
-
- # Make sure it's a valid key
- assert_nothing_raised("Created key is invalid") do
- OpenSSL::PKey::RSA.new(File.read(Puppet[:hostprivkey]))
- end
-
- # now make sure we can read it in
- other = CertUser.new
- assert_nothing_raised("Could not read key in") do
- other.key
- end
-
- assert_equal(@user.key.to_s, other.key.to_s, "Keys are not equal")
- end
-
- def test_csr
- csr = nil
- assert_nothing_raised("Could not create csr") do
- csr = @user.csr
- end
-
- assert(FileTest.exists?(Puppet[:hostcsr]), "did not create csr file")
- assert_instance_of(OpenSSL::X509::Request, csr)
- end
-
- def test_cacert
- @user = CertUser.new
-
- assert_raise(MissingCertificate, "Did not fail when missing cacert") do
- @user.ca_cert
- end
- end
-
- # Fixing #1382. This test will always fail on Darwin, because its
- # FS is case-insensitive.
- unless Facter.value(:operatingsystem) == "Darwin"
- def test_uppercase_files_are_renamed_and_read
- # Write a key out to disk in a file containing upper-case.
- key = OpenSSL::PKey::RSA.new(32)
- should_path = Puppet[:hostprivkey]
-
- dir, file = File.split(should_path)
- newfile = file.sub(/^([-a-z.0-9]+)\./) { $1.upcase + "."}
- upper_path = File.join(dir, newfile)
-p upper_path
- File.open(upper_path, "w") { |f| f.print key.to_s }
-
- user = CertUser.new
-
- assert_equal(key.to_s, user.read_key.to_s, "Did not read key in from disk")
- assert(! FileTest.exist?(upper_path), "Upper case file was not removed")
- assert(FileTest.exist?(should_path), "File was not renamed to lower-case file")
- assert_equal(key.to_s, user.read_key.to_s, "Did not read key in from disk")
- end
- end
-end
diff --git a/test/language/functions.rb b/test/language/functions.rb
index 44d86f0f9..2810b123a 100755
--- a/test/language/functions.rb
+++ b/test/language/functions.rb
@@ -1,541 +1,540 @@
#!/usr/bin/env ruby
require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
require 'puppet'
require 'puppet/parser/parser'
-require 'puppet/network/client'
require 'puppettest'
require 'puppettest/resourcetesting'
class TestLangFunctions < Test::Unit::TestCase
include PuppetTest::ParserTesting
include PuppetTest::ResourceTesting
def test_functions
Puppet::Node::Environment.stubs(:current).returns nil
assert_nothing_raised do
Puppet::Parser::AST::Function.new(
:name => "fakefunction",
:arguments => AST::ASTArray.new(
:children => [nameobj("avalue")]
)
)
end
assert_raise(Puppet::ParseError) do
func = Puppet::Parser::AST::Function.new(
:name => "fakefunction",
:arguments => AST::ASTArray.new(
:children => [nameobj("avalue")]
)
)
func.evaluate(mkscope)
end
assert_nothing_raised do
Puppet::Parser::Functions.newfunction(:fakefunction, :type => :rvalue) do |input|
return "output #{input[0]}"
end
end
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "fakefunction",
:ftype => :rvalue,
:arguments => AST::ASTArray.new(
:children => [nameobj("avalue")]
)
)
end
scope = mkscope
val = nil
assert_nothing_raised do
val = func.evaluate(scope)
end
assert_equal("output avalue", val)
end
def test_taggedfunction
scope = mkscope
scope.resource.tag("yayness")
# Make sure the ast stuff does what it's supposed to
{"yayness" => true, "booness" => false}.each do |tag, retval|
func = taggedobj(tag, :rvalue)
val = nil
assert_nothing_raised do
val = func.evaluate(scope)
end
assert_equal(retval, val, "'tagged' returned #{val} for #{tag}")
end
# Now make sure we correctly get tags.
scope.resource.tag("resourcetag")
assert(scope.function_tagged("resourcetag"), "tagged function did not catch resource tags")
scope.compiler.catalog.tag("configtag")
assert(scope.function_tagged("configtag"), "tagged function did not catch catalog tags")
end
def test_failfunction
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "fail",
:ftype => :statement,
:arguments => AST::ASTArray.new(
:children => [stringobj("this is a failure"), stringobj("and another")]
)
)
end
scope = mkscope
val = nil
assert_raise(Puppet::ParseError) do
val = func.evaluate(scope)
end
end
def test_multipletemplates
Dir.mkdir(Puppet[:templatedir])
onep = File.join(Puppet[:templatedir], "one")
twop = File.join(Puppet[:templatedir], "two")
File.open(onep, "w") do |f|
f.puts "<%- if @one.nil? then raise '@one undefined' end -%>template <%= @one %>"
end
File.open(twop, "w") do |f|
f.puts "template <%= @two %>"
end
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "template",
:ftype => :rvalue,
:arguments => AST::ASTArray.new(
:children => [stringobj("one"), stringobj("two")]
)
)
end
ast = varobj("output", func)
scope = mkscope
# Test that our manual exception throw fails the parse
assert_raise(Puppet::ParseError) do
ast.evaluate(scope)
end
# Test that our use of an undefined instance variable does not throw
# an exception, but only safely continues.
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['output'], "Undefined template variables do not raise exceptions")
# Now, fill in the last variable and make sure the whole thing
# evaluates correctly.
scope['two'] = "Two"
scope.unsetvar("output")
assert_nothing_raised do
ast.evaluate(scope)
end
assert_equal(
"template One\ntemplate Two\n", scope['output'],
"Templates were not handled correctly")
end
# Now make sure we can fully qualify files, and specify just one
def test_singletemplates
template = tempfile
File.open(template, "w") do |f|
f.puts "template <%= @yay.nil?() ? raise('yay undefined') : @yay %>"
end
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "template",
:ftype => :rvalue,
:arguments => AST::ASTArray.new(
:children => [stringobj(template)]
)
)
end
ast = varobj("output", func)
scope = mkscope
assert_raise(Puppet::ParseError) do
ast.evaluate(scope)
end
scope['yay'] = "this is yay"
assert_nothing_raised do
ast.evaluate(scope)
end
assert_equal(
"template this is yay\n", scope['output'],
"Templates were not handled correctly")
end
# Make sure that legacy template variable access works as expected.
def test_legacyvariables
template = tempfile
File.open(template, "w") do |f|
f.puts "template <%= deprecated %>"
end
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "template",
:ftype => :rvalue,
:arguments => AST::ASTArray.new(
:children => [stringobj(template)]
)
)
end
ast = varobj("output", func)
# Verify that we get an exception using old-style accessors.
scope = mkscope
assert_raise(Puppet::ParseError) do
ast.evaluate(scope)
end
# Verify that we evaluate and return their value correctly.
scope["deprecated"] = "deprecated value"
assert_nothing_raised do
ast.evaluate(scope)
end
assert_equal(
"template deprecated value\n", scope['output'],
"Deprecated template variables were not handled correctly")
end
# Make sure that problems with kernel method visibility still exist.
def test_kernel_module_shadows_deprecated_var_lookup
template = tempfile
File.open(template, "w").puts("<%= binding %>")
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "template",
:ftype => :rvalue,
:arguments => AST::ASTArray.new(
:children => [stringobj(template)]
)
)
end
ast = varobj("output", func)
# Verify that Kernel methods still shadow deprecated variable lookups.
scope = mkscope
assert_nothing_raised("No exception for Kernel shadowed variable names") do
ast.evaluate(scope)
end
end
def test_tempatefunction_cannot_see_scopes
template = tempfile
File.open(template, "w") do |f|
f.puts "<%= lookupvar('myvar') %>"
end
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "template",
:ftype => :rvalue,
:arguments => AST::ASTArray.new(
:children => [stringobj(template)]
)
)
end
ast = varobj("output", func)
scope = mkscope
scope['myvar'] = "this is yayness"
assert_raise(Puppet::ParseError) do
ast.evaluate(scope)
end
end
def test_template_reparses
template = tempfile
File.open(template, "w") do |f|
f.puts "original text"
end
file = tempfile
Puppet[:code] = %{file { "#{file}": content => template("#{template}") }}
Puppet[:environment] = "yay"
node = mknode
node.stubs(:environment).returns Puppet::Node::Environment.new
Puppet[:environment] = "yay"
catalog = Puppet::Parser::Compiler.new(node).compile
version = catalog.version
fileobj = catalog.vertices.find { |r| r.title == file }
assert(fileobj, "File was not in catalog")
assert_equal(
"original text\n", fileobj["content"],
"Template did not work")
Puppet[:filetimeout] = -5
# Have to sleep because one second is the fs's time granularity.
sleep(1)
# Now modify the template
File.open(template, "w") do |f|
f.puts "new text"
end
newversion = Puppet::Parser::Compiler.new(node).compile.version
assert(version != newversion, "Parse date did not change")
end
def test_template_defined_vars
template = tempfile
File.open(template, "w") do |f|
f.puts "template <%= @yayness %>"
end
func = nil
assert_nothing_raised do
func = Puppet::Parser::AST::Function.new(
:name => "template",
:ftype => :rvalue,
:arguments => AST::ASTArray.new(
:children => [stringobj(template)]
)
)
end
ast = varobj("output", func)
{
"" => "",
false => "false",
}.each do |string, value|
scope = mkscope
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['output'],
"#{string.inspect} did not get evaluated correctly")
end
end
def test_autoloading_functions
#assert_equal(false, Puppet::Parser::Functions.function(:autofunc),
# "Got told autofunc already exists")
dir = tempfile
$LOAD_PATH << dir
newpath = File.join(dir, "puppet", "parser", "functions")
FileUtils.mkdir_p(newpath)
File.open(File.join(newpath, "autofunc.rb"), "w") { |f|
f.puts %{
Puppet::Parser::Functions.newfunction(:autofunc, :type => :rvalue) do |vals|
Puppet.wanring vals.inspect
end
}
}
Puppet::Node::Environment.stubs(:current).returns nil
obj = nil
assert_nothing_raised {
obj = Puppet::Parser::Functions.function(:autofunc)
}
assert(obj, "Did not autoload function")
assert(Puppet::Parser::Functions.environment_module.method_defined?(:function_autofunc), "Did not set function correctly")
end
def test_search
scope = mkscope
fun = scope.known_resource_types.add Puppet::Resource::Type.new(:definition, "yay::ness")
foo = scope.known_resource_types.add Puppet::Resource::Type.new(:definition, "foo::bar")
search = Puppet::Parser::Functions.function(:search)
scope.function_search(["foo", "yay"])
ffun = ffoo = nil
assert_nothing_raised("Search path change did not work") do
ffun = scope.find_definition("ness")
ffoo = scope.find_definition('bar')
end
assert(ffun, "Could not find definition in 'fun' namespace")
assert(ffoo, "Could not find definition in 'foo' namespace")
end
def test_include
scope = mkscope
parser = mkparser
include = Puppet::Parser::Functions.function(:include)
assert_raise(Puppet::Error, "did not throw error on missing class") do
scope.function_include("nosuchclass")
end
scope.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "myclass", {})
scope.compiler.expects(:evaluate_classes).with(%w{myclass otherclass}, scope, false).returns(%w{myclass otherclass})
assert_nothing_raised do
scope.function_include(["myclass", "otherclass"])
end
end
def test_file
parser = mkparser
scope = mkscope(:parser => parser)
file = Puppet::Parser::Functions.function(:file)
file1 = tempfile
file2 = tempfile
file3 = tempfile
File.open(file2, "w") { |f| f.puts "yaytest" }
val = nil
assert_nothing_raised("Failed to call file with one arg") do
val = scope.function_file([file2])
end
assert_equal("yaytest\n", val, "file() failed")
assert_nothing_raised("Failed to call file with two args") do
val = scope.function_file([file1, file2])
end
assert_equal("yaytest\n", val, "file() failed")
assert_raise(Puppet::ParseError, "did not fail when files are missing") do
val = scope.function_file([file1, file3])
end
end
def test_generate
command = tempfile
sh = %x{which sh}
File.open(command, "w") do |f|
f.puts %{#!#{sh}
if [ -n "$1" ]; then
echo "yay-$1"
else
echo yay
fi
}
end
File.chmod(0755, command)
assert_equal("yay\n", %x{#{command}}, "command did not work")
assert_equal("yay-foo\n", %x{#{command} foo}, "command did not work")
Puppet::Node::Environment.stubs(:current).returns nil
generate = Puppet::Parser::Functions.function(:generate)
scope = mkscope
parser = mkparser
val = nil
assert_nothing_raised("Could not call generator with no args") do
val = scope.function_generate([command])
end
assert_equal("yay\n", val, "generator returned wrong results")
assert_nothing_raised("Could not call generator with args") do
val = scope.function_generate([command, "foo"])
end
assert_equal("yay-foo\n", val, "generator returned wrong results")
assert_raise(Puppet::ParseError, "Did not fail with an unqualified path") do
val = scope.function_generate([File.basename(command), "foo"])
end
assert_raise(Puppet::ParseError, "Did not fail when command failed") do
val = scope.function_generate([%x{which touch}.chomp, "/this/dir/does/not/exist"])
end
fake = File.join(File.dirname(command), "..")
dir = File.dirname(command)
dirname = File.basename(dir)
bad = File.join(dir, "..", dirname, File.basename(command))
assert_raise(Puppet::ParseError, "Did not fail when command failed") do
val = scope.function_generate([bad])
end
end
end
diff --git a/test/language/snippets.rb b/test/language/snippets.rb
index bfc14fa2d..f34e3684e 100755
--- a/test/language/snippets.rb
+++ b/test/language/snippets.rb
@@ -1,522 +1,513 @@
#!/usr/bin/env ruby
require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
require 'puppet'
require 'puppet/parser/parser'
-require 'puppet/network/client'
-require 'puppet/network/handler'
require 'puppettest'
class TestSnippets < Test::Unit::TestCase
include PuppetTest
def setup
super
@file = Puppet::Type.type(:file)
Facter.stubs(:to_hash).returns({})
Facter.stubs(:value).returns("whatever")
end
def self.snippetdir
PuppetTest.datadir "snippets"
end
def assert_file(path, msg = nil)
unless file = @catalog.resource(:file, path)
msg ||= "Could not find file #{path}"
raise msg
end
end
def assert_not_file(path, msg = nil)
if file = @catalog.resource(:file, path)
msg ||= "File #{path} exists!"
raise msg
end
end
def assert_mode_equal(mode, path)
if mode.is_a? Integer
mode = mode.to_s(8)
end
unless file = @catalog.resource(:file, path)
raise "Could not find file #{path}"
end
unless mode == file.should(:mode)
raise "Mode for %s is incorrect: %o vs %o" % [path, mode, file.should(:mode)]
end
end
def snippet(name)
File.join(self.class.snippetdir, name)
end
def file2ast(file)
parser = Puppet::Parser::Parser.new
parser.file = file
ast = parser.parse
ast
end
def snippet2ast(text)
parser = Puppet::Parser::Parser.new
parser.string = text
ast = parser.parse
ast
end
- def client
- args = {
- :Listen => false
- }
- Puppet::Network::Client.new(args)
- end
-
def ast2scope(ast)
scope = Puppet::Parser::Scope.new
ast.evaluate(scope)
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
def metaparams(type)
mparams = []
Puppet::Type.eachmetaparam { |param|
mparams.push param
}
mparams
end
def params(type)
params = []
type.parameters.each { |name,property|
params.push name
}
params
end
def randthing(thing,type)
list = self.send(thing,type)
list[rand(list.length)]
end
def randeach(type)
[:properties, :metaparams, :parameters].collect { |thing|
randthing(thing,type)
}
end
@@snippets = {
true => [
%{File { mode => 755 }}
],
}
def disabled_test_defaults
Puppet::Type.eachtype { |type|
next if type.name == :puppet or type.name == :component
rands = randeach(type)
name = type.name.to_s.capitalize
[0..1, 0..2].each { |range|
params = rands[range]
paramstr = params.collect { |param|
"#{param} => fake"
}.join(", ")
str = "#{name} { #{paramstr} }"
scope = nil
assert_nothing_raised {
scope = snippet2scope(str)
}
defaults = nil
assert_nothing_raised {
defaults = scope.lookupdefaults(name)
}
p defaults
params.each { |param|
puts "#{name} => '#{param}'"
assert(defaults.include?(param))
}
}
}
end
# this is here in case no tests get defined; otherwise we get a warning
def test_nothing
end
def snippet_filecreate
%w{a b c d}.each { |letter|
path = "/tmp/create#{letter}test"
assert_file(path)
assert_mode_equal(0755, path) if %w{a b}.include?(letter)
}
end
def snippet_simpledefaults
path = "/tmp/defaulttest"
assert_file(path)
assert_mode_equal(0755, path)
end
def snippet_simpleselector
files = %w{a b c d}.collect { |letter|
path = "/tmp/snippetselect#{letter}test"
assert_file(path)
assert_mode_equal(0755, path)
}
end
def snippet_classpathtest
path = "/tmp/classtest"
file = @catalog.resource(:file, path)
assert(file, "did not create file #{path}")
assert_equal( "/Stage[main]/Testing/Mytype[componentname]/File[/tmp/classtest]", file.path)
end
def snippet_argumentdefaults
path1 = "/tmp/argumenttest1"
path2 = "/tmp/argumenttest2"
file1 = @catalog.resource(:file, path1)
file2 = @catalog.resource(:file, path2)
assert_file(path1)
assert_mode_equal(0755, path1)
assert_file(path2)
assert_mode_equal(0644, path2)
end
def snippet_casestatement
paths = %w{
/tmp/existsfile
/tmp/existsfile2
/tmp/existsfile3
/tmp/existsfile4
/tmp/existsfile5
/tmp/existsfile6
}
paths.each { |path|
file = @catalog.resource(:file, path)
assert(file, "File #{path} is missing")
assert_mode_equal(0755, path)
}
end
def snippet_implicititeration
paths = %w{a b c d e f g h}.collect { |l| "/tmp/iteration#{l}test" }
paths.each { |path|
file = @catalog.resource(:file, path)
assert_file(path)
assert_mode_equal(0755, path)
}
end
def snippet_multipleinstances
paths = %w{a b c}.collect { |l| "/tmp/multipleinstances#{l}" }
paths.each { |path|
assert_file(path)
assert_mode_equal(0755, path)
}
end
def snippet_namevartest
file = "/tmp/testfiletest"
dir = "/tmp/testdirtest"
assert_file(file)
assert_file(dir)
assert_equal(:directory, @catalog.resource(:file, dir).should(:ensure), "Directory is not set to be a directory")
end
def snippet_scopetest
file = "/tmp/scopetest"
assert_file(file)
assert_mode_equal(0755, file)
end
def snippet_selectorvalues
nums = %w{1 2 3 4 5 6 7}
files = nums.collect { |n|
"/tmp/selectorvalues#{n}"
}
files.each { |f|
assert_file(f)
assert_mode_equal(0755, f)
}
end
def snippet_singleselector
nums = %w{1 2 3}
files = nums.collect { |n|
"/tmp/singleselector#{n}"
}
files.each { |f|
assert_file(f)
assert_mode_equal(0755, f)
}
end
def snippet_falsevalues
file = "/tmp/falsevaluesfalse"
assert_file(file)
end
def disabled_snippet_classargtest
[1,2].each { |num|
file = "/tmp/classargtest#{num}"
assert_file(file)
assert_mode_equal(0755, file)
}
end
def snippet_classheirarchy
[1,2,3].each { |num|
file = "/tmp/classheir#{num}"
assert_file(file)
assert_mode_equal(0755, file)
}
end
def snippet_singleary
[1,2,3,4].each { |num|
file = "/tmp/singleary#{num}"
assert_file(file)
}
end
def snippet_classincludes
[1,2,3].each { |num|
file = "/tmp/classincludes#{num}"
assert_file(file)
assert_mode_equal(0755, file)
}
end
def snippet_componentmetaparams
["/tmp/component1", "/tmp/component2"].each { |file|
assert_file(file)
}
end
def snippet_aliastest
%w{/tmp/aliastest /tmp/aliastest2 /tmp/aliastest3}.each { |file|
assert_file(file)
}
end
def snippet_singlequote
{ 1 => 'a $quote',
2 => 'some "\yayness\"'
}.each { |count, str|
path = "/tmp/singlequote#{count}"
assert_file(path)
assert_equal(str, @catalog.resource(:file, path).parameter(:content).actual_content)
}
end
# There's no way to actually retrieve the list of classes from the
# transaction.
def snippet_tag
end
# Make sure that set tags are correctly in place, yo.
def snippet_tagged
tags = {"testing" => true, "yayness" => false,
"both" => false, "bothtrue" => true, "define" => true}
tags.each do |tag, retval|
assert_file("/tmp/tagged#{tag}#{retval.to_s}")
end
end
def snippet_defineoverrides
file = "/tmp/defineoverrides1"
assert_file(file)
assert_mode_equal(0755, file)
end
def snippet_deepclassheirarchy
5.times { |i|
i += 1
file = "/tmp/deepclassheir#{i}"
assert_file(file)
}
end
def snippet_emptyclass
# There's nothing to check other than that it works
end
def snippet_emptyexec
assert(@catalog.resource(:exec, "touch /tmp/emptyexectest"), "Did not create exec")
end
def snippet_multisubs
path = "/tmp/multisubtest"
assert_file(path)
file = @catalog.resource(:file, path)
assert_equal("{md5}5fbef65269a99bddc2106251dd89b1dc", file.should(:content), "sub2 did not override content")
assert_mode_equal(0755, path)
end
def snippet_collection
assert_file("/tmp/colltest1")
assert_nil(@catalog.resource(:file, "/tmp/colltest2"), "Incorrectly collected file")
end
def snippet_virtualresources
%w{1 2 3 4}.each do |num|
assert_file("/tmp/virtualtest#{num}")
end
end
def snippet_componentrequire
%w{1 2}.each do |num|
assert_file(
"/tmp/testing_component_requires#{num}",
"#{num} does not exist")
end
end
def snippet_realize_defined_types
assert_file("/tmp/realize_defined_test1")
assert_file("/tmp/realize_defined_test2")
end
def snippet_collection_within_virtual_definitions
assert_file("/tmp/collection_within_virtual_definitions1_foo.txt")
assert_file("/tmp/collection_within_virtual_definitions2_foo2.txt")
end
def snippet_fqparents
assert_file("/tmp/fqparent1", "Did not make file from parent class")
assert_file("/tmp/fqparent2", "Did not make file from subclass")
end
def snippet_fqdefinition
assert_file("/tmp/fqdefinition", "Did not make file from fully-qualified definition")
end
def snippet_subclass_name_duplication
assert_file("/tmp/subclass_name_duplication1", "Did not make first file from duplicate subclass names")
assert_file("/tmp/subclass_name_duplication2", "Did not make second file from duplicate subclass names")
end
def snippet_funccomma
assert_file("/tmp/funccomma1", "Did not make first file from trailing function comma")
assert_file("/tmp/funccomma2", "Did not make second file from trailing function comma")
end
def snippet_arraytrailingcomma
assert_file("/tmp/arraytrailingcomma1", "Did not make first file from array")
assert_file("/tmp/arraytrailingcomma2", "Did not make second file from array")
end
def snippet_multipleclass
assert_file("/tmp/multipleclassone", "one")
assert_file("/tmp/multipleclasstwo", "two")
end
def snippet_multilinecomments
assert_not_file("/tmp/multilinecomments","Did create a commented resource");
end
def snippet_collection_override
path = "/tmp/collection"
assert_file(path)
assert_mode_equal(0600, path)
end
def snippet_ifexpression
assert_file("/tmp/testiftest","if test");
end
def snippet_hash
assert_file("/tmp/myhashfile1","hash test 1");
assert_file("/tmp/myhashfile2","hash test 2");
assert_file("/tmp/myhashfile3","hash test 3");
assert_file("/tmp/myhashfile4","hash test 4");
end
# Iterate across each of the snippets and create a test.
Dir.entries(snippetdir).sort.each { |file|
next if file =~ /^\./
mname = "snippet_" + file.sub(/\.pp$/, '')
if self.method_defined?(mname)
#eval("alias #{testname} #{mname}")
testname = ("test_#{mname}").intern
self.send(:define_method, testname) {
Puppet[:manifest] = snippet(file)
facts = {
"hostname" => "testhost",
"domain" => "domain.com",
"ipaddress" => "127.0.0.1",
"fqdn" => "testhost.domain.com"
}
node = Puppet::Node.new("testhost")
node.merge(facts)
catalog = nil
assert_nothing_raised("Could not compile catalog") {
catalog = Puppet::Resource::Catalog.indirection.find(node)
}
assert_nothing_raised("Could not convert catalog") {
catalog = catalog.to_ral
}
@catalog = catalog
assert_nothing_raised {
self.send(mname)
}
}
mname = mname.intern
end
}
end
diff --git a/test/lib/puppettest/exetest.rb b/test/lib/puppettest/exetest.rb
index 5a2248dc9..09626ff0d 100644
--- a/test/lib/puppettest/exetest.rb
+++ b/test/lib/puppettest/exetest.rb
@@ -1,125 +1,125 @@
require 'puppettest/servertest'
module PuppetTest::ExeTest
include PuppetTest::ServerTest
def setup
super
setbindir
setlibdir
end
def bindir
File.join(basedir, "bin")
end
def sbindir
File.join(basedir, "sbin")
end
def setbindir
ENV["PATH"] = [bindir, ENV["PATH"]].join(":") unless ENV["PATH"].split(":").include?(bindir)
ENV["PATH"] = [sbindir, ENV["PATH"]].join(":") unless ENV["PATH"].split(":").include?(sbindir)
end
def setlibdir
ENV["RUBYLIB"] = $LOAD_PATH.find_all { |dir|
dir =~ /puppet/ or dir =~ /\.\./
}.join(":")
end
# Run a ruby command. This explicitly uses ruby to run stuff, since we
# don't necessarily know where our ruby binary is, dernit.
# Currently unused, because I couldn't get it to work.
def rundaemon(*cmd)
@ruby ||= %x{which ruby}.chomp
cmd = cmd.unshift(@ruby).join(" ")
out = nil
Dir.chdir(bindir) {
out = %x{#{@ruby} #{cmd}}
}
out
end
def startmasterd(args = "")
output = nil
manifest = mktestmanifest
args += " --manifest #{manifest}"
args += " --confdir #{Puppet[:confdir]}"
args += " --rundir #{File.join(Puppet[:vardir], "run")}"
args += " --vardir #{Puppet[:vardir]}"
- args += " --certdnsnames #{Puppet[:certdnsnames]}"
+ args += " --dns_alt_names #{Puppet[:master_dns_alt_names]}"
args += " --masterport #{@@port}"
args += " --user #{Puppet::Util::SUIDManager.uid}"
args += " --group #{Puppet::Util::SUIDManager.gid}"
args += " --autosign true"
#if Puppet[:debug]
# args += " --debug"
#end
cmd = "puppetmasterd #{args}"
assert_nothing_raised {
output = %x{#{cmd}}.chomp
}
assert_equal("", output, "Puppetmasterd produced output #{output}")
assert($CHILD_STATUS == 0, "Puppetmasterd exit status was #{$CHILD_STATUS}")
sleep(1)
cleanup do
stopmasterd
sleep(1)
end
manifest
end
def stopmasterd(running = true)
ps = Facter["ps"].value || "ps -ef"
pidfile = File.join(Puppet[:vardir], "run", "puppetmasterd.pid")
pid = nil
if FileTest.exists?(pidfile)
pid = File.read(pidfile).chomp.to_i
File.unlink(pidfile)
end
return unless running
if running or pid
runningpid = nil
%x{#{ps}}.chomp.split(/\n/).each { |line|
if line =~ /ruby.+puppetmasterd/
next if line =~ /\.rb/ # skip the test script itself
next if line =~ /^puppet/ # skip masters running as 'puppet'
ary = line.sub(/^\s+/, '').split(/\s+/)
pid = ary[1].to_i
end
}
end
# we default to mandating that it's running, but teardown
# doesn't require that
if pid
if pid == $PID
raise Puppet::Error, "Tried to kill own pid"
end
begin
Process.kill(:INT, pid)
rescue
# ignore it
end
end
end
def teardown
stopmasterd(false)
super
end
end
diff --git a/test/lib/puppettest/servertest.rb b/test/lib/puppettest/servertest.rb
index 4174c1a3d..82483004d 100644
--- a/test/lib/puppettest/servertest.rb
+++ b/test/lib/puppettest/servertest.rb
@@ -1,74 +1,73 @@
require 'puppettest'
-require 'puppet/network/http_server/webrick'
module PuppetTest::ServerTest
include PuppetTest
def setup
super
if defined?(@@port)
@@port += 1
else
@@port = 20000
end
end
# create a simple manifest that just creates a file
def mktestmanifest
file = File.join(Puppet[:confdir], "#{(self.class.to_s + "test")}site.pp")
#@createdfile = File.join(tmpdir, self.class.to_s + "manifesttesting" +
# "_#{@method_name}")
@createdfile = tempfile
File.open(file, "w") { |f|
f.puts "file { \"%s\": ensure => file, mode => 755 }\n" % @createdfile
}
@@tmpfiles << @createdfile
@@tmpfiles << file
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/network/client/ca.rb b/test/network/client/ca.rb
deleted file mode 100755
index fcb950174..000000000
--- a/test/network/client/ca.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'mocha'
-require 'puppettest'
-require 'puppet/network/client/ca'
-require 'puppet/sslcertificates/support'
-
-class TestClientCA < Test::Unit::TestCase
- include PuppetTest::ServerTest
-
- def setup
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- super
- @ca = Puppet::Network::Handler.ca.new
- @client = Puppet::Network::Client.ca.new :CA => @ca
- end
-
- def test_request_cert
- assert_nothing_raised("Could not request cert") do
- @client.request_cert
- end
-
- [:hostprivkey, :hostcert, :localcacert].each do |name|
- assert(FileTest.exists?(Puppet.settings[name]), "Did not create cert #{name}")
- end
- end
-
- # Make sure the ca defaults to specific ports and names
- def test_ca_server
- Puppet.settings.stubs(:value).returns "eh"
- Puppet.settings.expects(:value).with(:ca_server).returns("myca")
- Puppet.settings.expects(:value).with(:ca_port).returns(321)
- Puppet.settings.stubs(:value).with(:http_proxy_host).returns(nil)
- Puppet.settings.stubs(:value).with(:http_proxy_port).returns(nil)
- Puppet.settings.stubs(:value).with(:http_keepalive).returns(false)
- Puppet.settings.stubs(:value).with(:configtimeout).returns(180)
-
- # Just throw an error; the important thing is the values, not what happens next.
- Net::HTTP.stubs(:new).with("myca", 321, nil, nil).raises(ArgumentError)
- assert_raise(ArgumentError) { Puppet::Network::Client.ca.new }
- end
-
- # #578
- def test_invalid_certs_are_not_written
- # Run the get once, which should be valid
-
- assert_nothing_raised("Could not get a certificate") do
- @client.request_cert
- end
-
- # Now remove the cert and keys, so we get a broken cert
- File.unlink(Puppet[:hostcert])
- File.unlink(Puppet[:localcacert])
- File.unlink(Puppet[:hostprivkey])
-
- @client = Puppet::Network::Client.ca.new :CA => @ca
- @ca.expects(:getcert).returns("yay") # not a valid cert
- # Now make sure it fails, since we'll get the old cert but have new keys
- assert_raise(Puppet::Network::Client::CA::InvalidCertificate, "Did not fail on invalid cert") do
- @client.request_cert
- end
-
- # And then make sure the cert isn't written to disk
- assert(! FileTest.exists?(Puppet[:hostcert]), "Invalid cert got written to disk")
- end
-end
-
diff --git a/test/network/client/dipper.rb b/test/network/client/dipper.rb
deleted file mode 100755
index 45f3a7a5c..000000000
--- a/test/network/client/dipper.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/file_bucket/dipper'
-
-class TestDipperClient < Test::Unit::TestCase
- include PuppetTest::ServerTest
-
- def setup
- super
- @dipper = Puppet::FileBucket::Dipper.new(:Path => tempfile)
- end
-
- # Make sure we can create a new file with 'restore'.
- def test_restore_to_new_file
- file = tempfile
- text = "asdf;lkajseofiqwekj"
- File.open(file, "w") { |f| f.puts text }
- md5 = nil
- assert_nothing_raised("Could not send file") do
- md5 = @dipper.backup(file)
- end
-
- newfile = tempfile
- assert_nothing_raised("could not restore to new path") do
- @dipper.restore(newfile, md5)
- end
-
- assert_equal(File.read(file), File.read(newfile), "did not restore correctly")
- end
-end
-
diff --git a/test/network/handler/ca.rb b/test/network/handler/ca.rb
deleted file mode 100755
index e27e9c29b..000000000
--- a/test/network/handler/ca.rb
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/handler/ca'
-require 'mocha'
-
-$short = (ARGV.length > 0 and ARGV[0] == "short")
-
-class TestCA < Test::Unit::TestCase
- include PuppetTest::ServerTest
-
- def setup
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- super
- end
-
- # Verify that we're autosigning. We have to autosign a "different" machine,
- # since we always autosign the CA server's certificate.
- def test_autocertgeneration
- ca = nil
-
- # create our ca
- assert_nothing_raised {
- ca = Puppet::Network::Handler.ca.new(:autosign => true)
- }
-
- # create a cert with a fake name
- key = nil
- csr = nil
- cert = nil
- hostname = "test.domain.com"
- assert_nothing_raised {
- cert = Puppet::SSLCertificates::Certificate.new(
- :name => "test.domain.com"
- )
- }
-
- # make the request
- assert_nothing_raised {
- cert.mkcsr
- }
-
- # and get it signed
- certtext = nil
- cacerttext = nil
- assert_nothing_raised {
- certtext, cacerttext = ca.getcert(cert.csr.to_s)
- }
-
- # they should both be strings
- assert_instance_of(String, certtext)
- assert_instance_of(String, cacerttext)
-
- # and they should both be valid certs
- assert_nothing_raised {
- OpenSSL::X509::Certificate.new(certtext)
- }
- assert_nothing_raised {
- OpenSSL::X509::Certificate.new(cacerttext)
- }
-
- # and pull it again, just to make sure we're getting the same thing
- newtext = nil
- assert_nothing_raised {
- newtext, cacerttext = ca.getcert(
- cert.csr.to_s, "test.reductivelabs.com", "127.0.0.1"
- )
- }
-
- assert_equal(certtext,newtext)
- end
-
- # this time don't use autosign
- def test_storeAndSign
- ca = nil
- caserv = nil
-
- # make our CA server
- assert_nothing_raised {
- caserv = Puppet::Network::Handler.ca.new(:autosign => false)
- }
-
- # retrieve the actual ca object
- assert_nothing_raised {
- ca = caserv.ca
- }
-
- # make our test cert again
- key = nil
- csr = nil
- cert = nil
- hostname = "test.domain.com"
- assert_nothing_raised {
- cert = Puppet::SSLCertificates::Certificate.new(
- :name => "anothertest.domain.com"
- )
- }
- # and the CSR
- assert_nothing_raised {
- cert.mkcsr
- }
-
- # retrieve them
- certtext = nil
- assert_nothing_raised {
- certtext, cacerttext = caserv.getcert(
- cert.csr.to_s, "test.reductivelabs.com", "127.0.0.1"
- )
- }
-
- # verify we got nothing back, since autosign is off
- assert_equal("", certtext)
-
- # now sign it manually, with the CA object
- x509 = nil
- assert_nothing_raised {
- x509, cacert = ca.sign(cert.csr)
- }
-
- # and write it out
- cert.cert = x509
- assert_nothing_raised {
- cert.write
- }
-
- assert(File.exists?(cert.certfile))
-
- # now get them again, and verify that we actually get them
- newtext = nil
- assert_nothing_raised {
- newtext, cacerttext = caserv.getcert(cert.csr.to_s)
- }
-
- assert(newtext)
- assert_nothing_raised {
- OpenSSL::X509::Certificate.new(newtext)
- }
-
- # Now verify that we can clean a given host's certs
- assert_nothing_raised {
- ca.clean("anothertest.domain.com")
- }
-
- assert(!File.exists?(cert.certfile), "Cert still exists after clean")
- end
-
- # and now test the autosign file
- def test_autosign
- autosign = File.join(tmpdir, "autosigntesting")
- @@tmpfiles << autosign
- File.open(autosign, "w") { |f|
- f.puts "hostmatch.domain.com"
- f.puts "*.other.com"
- }
-
- caserv = nil
- assert_nothing_raised {
- caserv = Puppet::Network::Handler.ca.new(:autosign => autosign)
- }
-
- # make sure we know what's going on
- assert(caserv.autosign?("hostmatch.domain.com"))
- assert(caserv.autosign?("fakehost.other.com"))
- assert(!caserv.autosign?("kirby.reductivelabs.com"))
- assert(!caserv.autosign?("culain.domain.com"))
- end
-
- # verify that things aren't autosigned by default
- def test_nodefaultautosign
- caserv = nil
- assert_nothing_raised {
- caserv = Puppet::Network::Handler.ca.new
- }
-
- # make sure we know what's going on
- assert(!caserv.autosign?("hostmatch.domain.com"))
- assert(!caserv.autosign?("fakehost.other.com"))
- assert(!caserv.autosign?("kirby.reductivelabs.com"))
- assert(!caserv.autosign?("culain.domain.com"))
- end
-
- # We want the CA to autosign its own certificate, because otherwise
- # the puppetmasterd CA does not autostart.
- def test_caautosign
- server = nil
- Puppet.stubs(:master?).returns true
- assert_nothing_raised {
-
- server = Puppet::Network::HTTPServer::WEBrick.new(
-
- :Port => @@port,
-
- :Handlers => {
- :CA => {}, # so that certs autogenerate
- :Status => nil
- }
- )
- }
- end
-
- # Make sure true/false causes the file to be ignored.
- def test_autosign_true_beats_file
- caserv = nil
- assert_nothing_raised {
- caserv = Puppet::Network::Handler.ca.new
- }
-
- host = "hostname.domain.com"
-
- # Create an autosign file
- file = tempfile
- Puppet[:autosign] = file
-
- File.open(file, "w") { |f|
- f.puts host
- }
-
- # Start with "false"
- Puppet[:autosign] = false
-
- assert(! caserv.autosign?(host), "Host was incorrectly autosigned")
-
- # Then set it to true
- Puppet[:autosign] = true
- assert(caserv.autosign?(host), "Host was not autosigned")
- # And try a different host
- assert(caserv.autosign?("other.yay.com"), "Host was not autosigned")
-
- # And lastly the file
- Puppet[:autosign] = file
- assert(caserv.autosign?(host), "Host was not autosigned")
-
- # And try a different host
- assert(! caserv.autosign?("other.yay.com"), "Host was autosigned")
- end
-
- # Make sure that a CSR created with keys that don't match the existing
- # cert throws an exception on the server.
- def test_mismatched_public_keys_throws_exception
- ca = Puppet::Network::Handler.ca.new
-
- # First initialize the server
- client = Puppet::Network::Client.ca.new :CA => ca
- client.request_cert
- File.unlink(Puppet[:hostcsr])
-
- # Now use a different cert name
- Puppet[:certname] = "my.host.com"
- client = Puppet::Network::Client.ca.new :CA => ca
- firstcsr = client.csr
- File.unlink(Puppet[:hostcsr]) if FileTest.exists?(Puppet[:hostcsr])
-
- assert_nothing_raised("Could not get cert") do
- ca.getcert(firstcsr.to_s)
- end
-
- # Now get rid of the public key, forcing a new csr
- File.unlink(Puppet[:hostprivkey])
-
- client = Puppet::Network::Client.ca.new :CA => ca
-
- second_csr = client.csr
-
- assert(firstcsr.to_s != second_csr.to_s, "CSR did not change")
-
- assert_raise(Puppet::Error, "CA allowed mismatched keys") do
- ca.getcert(second_csr.to_s)
- end
- end
-end
-
diff --git a/test/network/server/mongrel_test.rb b/test/network/server/mongrel_test.rb
deleted file mode 100755
index ca215ee25..000000000
--- a/test/network/server/mongrel_test.rb
+++ /dev/null
@@ -1,99 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'mocha'
-
-class TestMongrelServer < PuppetTest::TestCase
- confine "Missing mongrel" => Puppet.features.mongrel?
-
- include PuppetTest::ServerTest
-
- def mkserver(handlers = nil)
- handlers ||= { :Status => nil }
- mongrel = Puppet::Network::HTTPServer::Mongrel.new(handlers)
- end
-
- # Make sure client info is correctly extracted.
- def test_client_info
- obj = Object.new
- obj.singleton_class.send(:attr_accessor, :params)
- params = {}
- obj.params = params
-
- mongrel = mkserver
-
- ip = Facter.value(:ipaddress)
- params["REMOTE_ADDR"] = ip
- params[Puppet[:ssl_client_header]] = ""
- params[Puppet[:ssl_client_verify_header]] = "failure"
- info = nil
- Resolv.expects(:getname).with(ip).returns("host.domain.com").times(4)
- assert_nothing_raised("Could not call client_info") do
- info = mongrel.send(:client_info, obj)
- end
- assert(! info.authenticated?, "Client info object was marked valid even though headers were missing")
- assert_equal(ip, info.ip, "Did not copy over ip correctly")
-
- assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
- # Now pass the X-Forwarded-For header and check it is preferred over REMOTE_ADDR
- params["REMOTE_ADDR"] = '127.0.0.1'
- params["HTTP_X_FORWARDED_FOR"] = ip
- info = nil
- assert_nothing_raised("Could not call client_info") do
- info = mongrel.send(:client_info, obj)
- end
- assert(! info.authenticated?, "Client info object was marked valid even though headers were missing")
- assert_equal(ip, info.ip, "Did not copy over ip correctly")
-
- assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
- # Now add a valid auth header.
- params["REMOTE_ADDR"] = ip
- params["HTTP_X_FORWARDED_FOR"] = nil
- params[Puppet[:ssl_client_header]] = "/CN=host.domain.com"
- assert_nothing_raised("Could not call client_info") do
- info = mongrel.send(:client_info, obj)
- end
- assert(! info.authenticated?, "Client info object was marked valid even though the verify header was fals")
- assert_equal(ip, info.ip, "Did not copy over ip correctly")
- assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
- # Now change the verify header to be true
- params[Puppet[:ssl_client_verify_header]] = "SUCCESS"
- assert_nothing_raised("Could not call client_info") do
- info = mongrel.send(:client_info, obj)
- end
-
- assert(info.authenticated?, "Client info object was not marked valid even though all headers were correct")
- assert_equal(ip, info.ip, "Did not copy over ip correctly")
- assert_equal("host.domain.com", info.name, "Did not copy over hostname correctly")
-
- # Now try it with a different header name
- params.delete(Puppet[:ssl_client_header])
- Puppet[:ssl_client_header] = "header_testing"
- params["header_testing"] = "/CN=other.domain.com"
- info = nil
- assert_nothing_raised("Could not call client_info with other header") do
- info = mongrel.send(:client_info, obj)
- end
-
- assert(info.authenticated?, "Client info object was not marked valid even though the header was present")
- assert_equal(ip, info.ip, "Did not copy over ip correctly")
- assert_equal("other.domain.com", info.name, "Did not copy over hostname correctly")
-
- # Now make sure it's considered invalid without that header
- params.delete("header_testing")
- info = nil
- assert_nothing_raised("Could not call client_info with no header") do
- info = mongrel.send(:client_info, obj)
- end
-
- assert(! info.authenticated?, "Client info object was marked valid without header")
- assert_equal(ip, info.ip, "Did not copy over ip correctly")
- assert_equal(Resolv.getname(ip), info.name, "Did not look up hostname correctly")
- end
-end
-
diff --git a/test/network/server/webrick.rb b/test/network/server/webrick.rb
deleted file mode 100755
index e1fd68921..000000000
--- a/test/network/server/webrick.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/http_server/webrick'
-require 'mocha'
-
-class TestWebrickServer < Test::Unit::TestCase
- include PuppetTest::ServerTest
-
- def setup
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- Puppet::SSL::Host.instance_variable_set(:@localhost, nil)
- super
- end
-
- # Make sure we can create a server, and that it knows how to create its
- # certs by default.
- def test_basics
- server = nil
- assert_raise(Puppet::Error, "server succeeded with no cert") do
- server = Puppet::Network::HTTPServer::WEBrick.new(
- :Port => @@port,
- :Handlers => {
- :Status => nil
- }
- )
- end
-
- assert_nothing_raised("Could not create simple server") do
- server = Puppet::Network::HTTPServer::WEBrick.new(
- :Port => @@port,
- :Handlers => {
- :CA => {}, # so that certs autogenerate
- :Status => nil
- }
- )
- end
-
- assert(server, "did not create server")
-
- assert(server.cert, "did not retrieve cert")
- end
-
- # test that we can connect to the server
- # we have to use fork here, because we apparently can't use threads
- # to talk to other threads
- def test_connect_with_fork
- Puppet[:autosign] = true
- serverpid, server = mk_status_server
-
- # create a status client, and verify it can talk
- client = mk_status_client
-
- assert(client.cert, "did not get cert for client")
-
- retval = nil
- assert_nothing_raised("Could not connect to server") {
- retval = client.status
- }
- assert_equal(1, retval)
- end
-
- def mk_status_client
- client = nil
-
- assert_nothing_raised {
- client = Puppet::Network::Client.status.new(
- :Server => "localhost",
- :Port => @@port
- )
- }
- client
- end
-
- def mk_status_server
- server = nil
- Puppet[:certdnsnames] = "localhost"
- assert_nothing_raised {
- server = Puppet::Network::HTTPServer::WEBrick.new(
- :Port => @@port,
- :Handlers => {
- :CA => {}, # so that certs autogenerate
- :Status => nil
- }
- )
- }
-
- pid = fork {
- Puppet.run_mode.stubs(:master?).returns true
- assert_nothing_raised {
- trap(:INT) { server.shutdown }
- server.start
- }
- }
- @@tmppids << pid
- [pid, server]
- end
-
- def kill_and_wait(pid, file)
- %x{kill -INT #{pid} 2>/dev/null}
- count = 0
- while count < 30 && File::exist?(file)
- count += 1
- sleep(1)
- end
- assert(count < 30, "Killing server #{pid} failed")
- end
-end
-
diff --git a/test/network/xmlrpc/client.rb b/test/network/xmlrpc/client.rb
deleted file mode 100755
index 73159a994..000000000
--- a/test/network/xmlrpc/client.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
-
-require 'puppettest'
-require 'puppet/network/xmlrpc/client'
-require 'mocha'
-
-class TestXMLRPCClient < Test::Unit::TestCase
- include PuppetTest
-
- def setup
- Puppet::Util::SUIDManager.stubs(:asuser).yields
- super
- end
-
- def test_set_backtrace
- error = Puppet::Network::XMLRPCClientError.new("An error")
- assert_nothing_raised do
- error.set_backtrace ["caller"]
- end
- assert_equal(["caller"], error.backtrace)
- end
-
- # Make sure we correctly generate a netclient
- def test_handler_class
- # Create a test handler
- klass = Puppet::Network::XMLRPCClient
- yay = Class.new(Puppet::Network::Handler) do
- @interface = XMLRPC::Service::Interface.new("yay") { |iface|
- iface.add_method("array getcert(csr)")
- }
-
- @name = :Yay
- end
- Object.const_set("Yay", yay)
-
- net = nil
- assert_nothing_raised("Failed when retrieving client for handler") do
- net = klass.handler_class(yay)
- end
-
- assert(net, "did not get net client")
- end
-end
diff --git a/test/rails/rails.rb b/test/rails/rails.rb
index 75987b95e..a9a750ffd 100755
--- a/test/rails/rails.rb
+++ b/test/rails/rails.rb
@@ -1,25 +1,24 @@
#!/usr/bin/env ruby
require File.expand_path(File.dirname(__FILE__) + '/../lib/puppettest')
require 'puppet'
require 'puppet/rails'
require 'puppet/parser/parser'
-require 'puppet/network/client'
require 'puppettest'
require 'puppettest/parsertesting'
require 'puppettest/resourcetesting'
require 'puppettest/railstesting'
class TestRails < Test::Unit::TestCase
include PuppetTest::ParserTesting
include PuppetTest::ResourceTesting
include PuppetTest::RailsTesting
def test_includerails
assert_nothing_raised {
require 'puppet/rails'
}
end
end
diff --git a/test/ral/type/filesources.rb b/test/ral/type/filesources.rb
index f39d53907..9cb7efbf0 100755
--- a/test/ral/type/filesources.rb
+++ b/test/ral/type/filesources.rb
@@ -1,506 +1,446 @@
#!/usr/bin/env ruby
require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest')
require 'puppettest'
require 'puppettest/support/utils'
require 'cgi'
require 'fileutils'
require 'mocha'
class TestFileSources < Test::Unit::TestCase
include PuppetTest::Support::Utils
include PuppetTest::FileTesting
def setup
super
if defined?(@port)
@port += 1
else
@port = 12345
end
@file = Puppet::Type.type(:file)
Puppet[:filetimeout] = -1
Puppet::Util::SUIDManager.stubs(:asuser).yields
Facter.stubs(:to_hash).returns({})
end
def teardown
super
end
def use_storage
initstorage
rescue
system("rm -rf #{Puppet[:statefile]}")
end
def initstorage
Puppet::Util::Storage.init
Puppet::Util::Storage.load
end
# Make a simple recursive tree.
def mk_sourcetree
source = tempfile
sourcefile = File.join(source, "file")
Dir.mkdir source
File.open(sourcefile, "w") { |f| f.puts "yay" }
dest = tempfile
destfile = File.join(dest, "file")
return source, dest, sourcefile, destfile
end
def recursive_source_test(fromdir, todir)
initstorage
tofile = nil
trans = nil
tofile = Puppet::Type.type(:file).new(
:path => todir,
:recurse => true,
:backup => false,
:source => fromdir
)
catalog = mk_catalog(tofile)
catalog.apply
assert(FileTest.exists?(todir), "Created dir #{todir} does not exist")
end
def run_complex_sources(networked = false)
path = tempfile
# first create the source directory
FileUtils.mkdir_p path
# okay, let's create a directory structure
fromdir = File.join(path,"fromdir")
Dir.mkdir(fromdir)
FileUtils.cd(fromdir) {
File.open("one", "w") { |f| f.puts "onefile"}
File.open("two", "w") { |f| f.puts "twofile"}
}
todir = File.join(path, "todir")
source = fromdir
source = "puppet://localhost/#{networked}#{fromdir}" if networked
recursive_source_test(source, todir)
[fromdir,todir, File.join(todir, "one"), File.join(todir, "two")]
end
def test_complex_sources_twice
fromdir, todir, one, two = run_complex_sources
assert_trees_equal(fromdir,todir)
recursive_source_test(fromdir, todir)
assert_trees_equal(fromdir,todir)
# Now remove the whole tree and try it again.
[one, two].each do |f| File.unlink(f) end
Dir.rmdir(todir)
recursive_source_test(fromdir, todir)
assert_trees_equal(fromdir,todir)
end
def test_sources_with_deleted_destfiles
fromdir, todir, one, two = run_complex_sources
assert(FileTest.exists?(todir))
# then delete a file
File.unlink(two)
# and run
recursive_source_test(fromdir, todir)
assert(FileTest.exists?(two), "Deleted file was not recopied")
# and make sure they're still equal
assert_trees_equal(fromdir,todir)
end
def test_sources_with_readonly_destfiles
fromdir, todir, one, two = run_complex_sources
assert(FileTest.exists?(todir))
File.chmod(0600, one)
recursive_source_test(fromdir, todir)
# and make sure they're still equal
assert_trees_equal(fromdir,todir)
# Now try it with the directory being read-only
File.chmod(0111, todir)
recursive_source_test(fromdir, todir)
# and make sure they're still equal
assert_trees_equal(fromdir,todir)
end
def test_sources_with_modified_dest_files
fromdir, todir, one, two = run_complex_sources
assert(FileTest.exists?(todir))
# Modify a dest file
File.open(two, "w") { |f| f.puts "something else" }
recursive_source_test(fromdir, todir)
# and make sure they're still equal
assert_trees_equal(fromdir,todir)
end
def test_sources_with_added_destfiles
fromdir, todir = run_complex_sources
assert(FileTest.exists?(todir))
# and finally, add some new files
add_random_files(todir)
recursive_source_test(fromdir, todir)
fromtree = file_list(fromdir)
totree = file_list(todir)
assert(fromtree != totree, "Trees are incorrectly equal")
# then remove our new files
FileUtils.cd(todir) {
%x{find . 2>/dev/null}.chomp.split(/\n/).each { |file|
if file =~ /file[0-9]+/
FileUtils.rm_rf(file)
end
}
}
# and make sure they're still equal
assert_trees_equal(fromdir,todir)
end
# Make sure added files get correctly caught during recursion
def test_RecursionWithAddedFiles
basedir = tempfile
Dir.mkdir(basedir)
@@tmpfiles << basedir
file1 = File.join(basedir, "file1")
file2 = File.join(basedir, "file2")
subdir1 = File.join(basedir, "subdir1")
file3 = File.join(subdir1, "file")
File.open(file1, "w") { |f| f.puts "yay" }
rootobj = nil
assert_nothing_raised {
rootobj = Puppet::Type.type(:file).new(
:name => basedir,
:recurse => true,
:check => %w{type owner},
:mode => 0755
)
}
assert_apply(rootobj)
assert_equal(0755, filemode(file1))
File.open(file2, "w") { |f| f.puts "rah" }
assert_apply(rootobj)
assert_equal(0755, filemode(file2))
Dir.mkdir(subdir1)
File.open(file3, "w") { |f| f.puts "foo" }
assert_apply(rootobj)
assert_equal(0755, filemode(file3))
end
def mkfileserverconf(mounts)
file = tempfile
File.open(file, "w") { |f|
mounts.each { |path, name|
f.puts "[#{name}]\n\tpath #{path}\n\tallow *\n"
}
}
@@tmpfiles << file
file
end
- def test_unmountedNetworkSources
- server = nil
- mounts = {
- "/" => "root",
- "/noexistokay" => "noexist"
- }
-
- fileserverconf = mkfileserverconf(mounts)
-
- Puppet[:autosign] = true
- Puppet[:masterport] = @port
- Puppet[:certdnsnames] = "localhost"
-
- serverpid = nil
- assert_nothing_raised("Could not start on port #{@port}") {
-
- server = Puppet::Network::HTTPServer::WEBrick.new(
-
- :Port => @port,
-
- :Handlers => {
- :CA => {}, # so that certs autogenerate
- :FileServer => {
- :Config => fileserverconf
- }
- }
- )
-
- }
-
- serverpid = fork {
- assert_nothing_raised {
- #trap(:INT) { server.shutdown; Kernel.exit! }
- trap(:INT) { server.shutdown }
- server.start
- }
- }
- @@tmppids << serverpid
-
- sleep(1)
-
- name = File.join(tmpdir, "nosourcefile")
-
- file = Puppet::Type.type(:file).new(
-
- :source => "puppet://localhost/noexist/file",
-
- :name => name
- )
-
- assert_raise Puppet::Error do
- file.retrieve
- end
-
- comp = mk_catalog(file)
- comp.apply
-
- assert(!FileTest.exists?(name), "File with no source exists anyway")
- end
-
def test_sourcepaths
files = []
3.times {
files << tempfile
}
to = tempfile
File.open(files[-1], "w") { |f| f.puts "yee-haw" }
file = nil
assert_nothing_raised {
file = Puppet::Type.type(:file).new(
:name => to,
:source => files
)
}
comp = mk_catalog(file)
assert_events([:file_created], comp)
assert(File.exists?(to), "File does not exist")
txt = nil
File.open(to) { |f| txt = f.read.chomp }
assert_equal("yee-haw", txt, "Contents do not match")
end
# Make sure that source-copying updates the checksum on the same run
def test_sourcebeatsensure
source = tempfile
dest = tempfile
File.open(source, "w") { |f| f.puts "yay" }
file = nil
assert_nothing_raised {
file = Puppet::Type.type(:file).new(
:name => dest,
:ensure => "file",
:source => source
)
}
file.retrieve
assert_events([:file_created], file)
file.retrieve
assert_events([], file)
assert_events([], file)
end
def test_sourcewithlinks
source = tempfile
link = tempfile
dest = tempfile
File.open(source, "w") { |f| f.puts "yay" }
File.symlink(source, link)
file = Puppet::Type.type(:file).new(:name => dest, :source => link)
catalog = mk_catalog(file)
# Default to managing links
catalog.apply
assert(FileTest.symlink?(dest), "Did not create link")
# Now follow the links
file[:links] = :follow
catalog.apply
assert(FileTest.file?(dest), "Destination is not a file")
end
# Make sure files aren't replaced when replace is false, but otherwise
# are.
def test_replace
dest = tempfile
file = Puppet::Type.newfile(
:path => dest,
:content => "foobar",
:recurse => true
)
assert_apply(file)
File.open(dest, "w") { |f| f.puts "yayness" }
file[:replace] = false
assert_apply(file)
# Make sure it doesn't change.
assert_equal("yayness\n", File.read(dest), "File got replaced when :replace was false")
file[:replace] = true
assert_apply(file)
# Make sure it changes.
assert_equal("foobar", File.read(dest), "File was not replaced when :replace was true")
end
def test_sourceselect
dest = tempfile
sources = []
2.times { |i|
i = i + 1
source = tempfile
sources << source
file = File.join(source, "file#{i}")
Dir.mkdir(source)
File.open(file, "w") { |f| f.print "yay" }
}
file1 = File.join(dest, "file1")
file2 = File.join(dest, "file2")
file3 = File.join(dest, "file3")
# Now make different files with the same name in each source dir
sources.each_with_index do |source, i|
File.open(File.join(source, "file3"), "w") { |f|
f.print i.to_s
}
end
obj = Puppet::Type.newfile(
:path => dest, :recurse => true,
:source => sources)
assert_equal(:first, obj[:sourceselect], "sourceselect has the wrong default")
# First, make sure we default to just copying file1
assert_apply(obj)
assert(FileTest.exists?(file1), "File from source 1 was not copied")
assert(! FileTest.exists?(file2), "File from source 2 was copied")
assert(FileTest.exists?(file3), "File from source 1 was not copied")
assert_equal("0", File.read(file3), "file3 got wrong contents")
# Now reset sourceselect
assert_nothing_raised do
obj[:sourceselect] = :all
end
File.unlink(file1)
File.unlink(file3)
Puppet.err :yay
assert_apply(obj)
assert(FileTest.exists?(file1), "File from source 1 was not copied")
assert(FileTest.exists?(file2), "File from source 2 was copied")
assert(FileTest.exists?(file3), "File from source 1 was not copied")
assert_equal("0", File.read(file3), "file3 got wrong contents")
end
def test_recursive_sourceselect
dest = tempfile
source1 = tempfile
source2 = tempfile
files = []
[source1, source2, File.join(source1, "subdir"), File.join(source2, "subdir")].each_with_index do |dir, i|
Dir.mkdir(dir)
# Make a single file in each directory
file = File.join(dir, "file#{i}")
File.open(file, "w") { |f| f.puts "yay#{i}"}
# Now make a second one in each directory
file = File.join(dir, "second-file#{i}")
File.open(file, "w") { |f| f.puts "yaysecond-#{i}"}
files << file
end
obj = Puppet::Type.newfile(:path => dest, :source => [source1, source2], :sourceselect => :all, :recurse => true)
assert_apply(obj)
["file0", "file1", "second-file0", "second-file1", "subdir/file2", "subdir/second-file2", "subdir/file3", "subdir/second-file3"].each do |file|
path = File.join(dest, file)
assert(FileTest.exists?(path), "did not create #{file}")
assert_equal("yay#{File.basename(file).sub("file", '')}\n", File.read(path), "file was not copied correctly")
end
end
# #594
def test_purging_missing_remote_files
source = tempfile
dest = tempfile
s1 = File.join(source, "file1")
s2 = File.join(source, "file2")
d1 = File.join(dest, "file1")
d2 = File.join(dest, "file2")
Dir.mkdir(source)
[s1, s2].each { |name| File.open(name, "w") { |file| file.puts "something" } }
# We have to add a second parameter, because that's the only way to expose the "bug".
file = Puppet::Type.newfile(:path => dest, :source => source, :recurse => true, :purge => true, :mode => "755")
assert_apply(file)
assert(FileTest.exists?(d1), "File1 was not copied")
assert(FileTest.exists?(d2), "File2 was not copied")
File.unlink(s2)
assert_apply(file)
assert(FileTest.exists?(d1), "File1 was not kept")
assert(! FileTest.exists?(d2), "File2 was not purged")
end
end

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 9:53 AM (1 d, 21 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
d6/c5/ae82b2ac38d74f3f851c8ebce2fa
Default Alt Text
(1 MB)

Event Timeline