diff options
| author | Dominic Cleal <dcleal@redhat.com> | 2010-11-27 13:36:04 +0000 |
|---|---|---|
| committer | Dominic Cleal <dcleal@redhat.com> | 2010-11-27 13:36:04 +0000 |
| commit | afe2d014feb2210a8666c93465d11e9c9d555f8b (patch) | |
| tree | 208f5ac82b2c29610d2021821c8fca9b079e638b | |
| parent | 143fc744a839affd328234fca26246d49d15d3d8 (diff) | |
| parent | 4b35402ba85d8842d757becec5c8a7bf4d6f6654 (diff) | |
| download | puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.tar.gz puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.tar.xz puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.zip | |
Merge branch 'master' of github.com:domcleal/puppet into master-old
394 files changed, 11982 insertions, 9217 deletions
@@ -1,5 +1,240 @@ +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 @@ -3427,10 +3662,6 @@ ada960b Constants in provider/interface/redhat.rb are getting redifined as they 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 - -0.23.2 -====== -49c9a62 Adding release tag REL_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. @@ -3460,10 +3691,6 @@ a8bf96a Adding a file that should have been in a commit from yesterda 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 - -0.23.1 -====== -0f7f752 Adding release tag REL_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. @@ -3554,10 +3781,6 @@ dc2a0bf Use single config file ada4355 Updated to version 0.23.0 d8f4c53 Updated to version 0.23.0 049faf8 Updated to version 0.23.0 - -0.23.0 -====== -f588d47 Adding release tag REL_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 @@ -3731,10 +3954,6 @@ 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 - -0.22.4 -====== -22ce899 Adding release tag REL_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. @@ -3798,10 +4017,6 @@ ca5d068 Updating the docs for the sourceselect parameter a999752 Updated to version 0.22.3 24ad5ab Updated to version 0.22.3 9ce7c79 Updated to version 0.22.3 - -0.22.3 -====== -a3a7ea7 Adding release tag REL_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. @@ -3825,10 +4040,6 @@ c5e1a44 Fixing the "readcert" method after getting the signed cert; the method 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 - -0.22.2 -====== -a917a3e Adding release tag REL_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 @@ -3983,10 +4194,6 @@ 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 - -0.22.1 -====== -530c255 Adding release tag REL_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 @@ -4078,10 +4285,6 @@ 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 - -0.22.0 -====== -728d745 Adding release tag REL_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 @@ -4260,10 +4463,6 @@ c3c5851 Fixing configuration storage -- there was a check being done that cause 60af8e2 Updated to version 0.20.1 e313a26 Updated to version 0.20.1 68d9e78 Updated to version 0.20.1 - -0.20.1 -====== -2feb9e8 Adding release tag REL_0_20_1 7d46167 Updating changelog for 0.20.1 7fa96cb Another small fix, just for solaris db5d9d4 Another testing fix @@ -4315,10 +4514,6 @@ e741b7b Fixing some Class.to_s handling 71924ad Updated to version 0.20.0 a488dd9 Updated to version 0.20.0 4688d93 Updated to version 0.20.0 - -0.20.0 -====== -7694bd9 Adding release tag 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 @@ -4440,16 +4635,6 @@ f2ac4dc Updating changelog for 0.19.3, and merging the version changes over. 8f9dcb5 Updated to version 0.19.2 595d5ba Updated to version 0.19.2 6902f2d Updated to version 0.19.2 - -0.19.3 -====== -bec795d Adding release tag REL_0_19_3 -0513ffa Fixing problem with the hostname being removed when running locally. The node_name setting was not checking that the client was set, and it is never set when running locally. -7726afc Adding branch to fix the problem with hostnames getting nilled - -0.19.2 -====== -ddb4c47 Adding release tag REL_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 @@ -4494,10 +4679,6 @@ 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 - -0.19.1 -====== -7e229a8 Adding release tag REL_0_19_2 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. @@ -4539,10 +4720,6 @@ c651b19 Disable the sample fileserver module by default, otherwise users get sp 65bb635 Updated to version 0.19.0 61e42e7 Updated to version 0.19.0 12b219e Updated to version 0.19.0 - -0.19.0 -====== -fbebcc5 Adding release tag REL_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 @@ -4660,10 +4837,6 @@ b2f1aa0 doc updates b8bf113 Updated to version 0.18.4 94cc68b Updated to version 0.18.4 ce95ee3 Updated to version 0.18.4 - -0.18.4 -====== -74a3b4d Adding release tag REL_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 @@ -4694,10 +4867,6 @@ e74b8af fixing html markup b23b797 Updated to version 0.18.3 fe8ce26 Updated to version 0.18.3 a984a90 Updated to version 0.18.3 - -0.18.3 -====== -04a99e7 Adding release tag REL_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. @@ -4727,10 +4896,6 @@ eff8d6e Accepting the patch from #190. bd9fd8d Updated to version 0.18.2 71036e7 Updated to version 0.18.2 aa87963 Updated to version 0.18.2 - -0.18.2 -====== -3e5907d Adding release tag REL_0_18_2 afe84ec small fixes towards 0.18.2 e17f4ed adding host information to reports and tagmail report 1503b42 renaming tagmail config file @@ -4761,10 +4926,6 @@ ea91896 changing the #!ruby lines to #!env ruby d275489 Updated to version 0.18.1 35ef37b Updated to version 0.18.1 427831c Updated to version 0.18.1 - -0.18.1 -====== -1cc2712 Adding release tag REL_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 @@ -4814,11 +4975,6 @@ e841d8f Adding test and fix for empty execs being ignored 0ab461b Updated to version 0.18.0 daac8cf Updated to version 0.18.0 8779dbe Updated to version 0.18.0 - -0.18.0 -====== -4a5df83 Adding release tag REL_0_18_0 -a6f9bf4 Adding release tag REL_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. @@ -4880,10 +5036,6 @@ b08816b Fixing #162. Node names must now be comma-separated. 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 - -0.17.2 -====== -b742236 Adding release tag REL_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. @@ -4893,10 +5045,6 @@ d55adda First version of puppetrun. It seems to mostly work, but I need to tes 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 - -0.17.1 -====== -f028420 Adding release tag REL_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. @@ -4904,10 +5052,6 @@ ed9adf5 updating changelog for 0.17.1 and 0.17.0 dc3a6d5 Making sure file recursion works for all valid inputs 373afa3 updating version on spec file 4296b02 Updated to version 0.17.0 - -0.17.0 -====== -559f4b0 Adding release tag REL_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 @@ -4939,27 +5083,15 @@ e06c661 Small bug fixes 18de804 fixing log messages a7fadbe fixing log messages 43fdd89 Updated to version 0.16.5 - -0.16.5 -====== -054cc77 Adding release tag REL_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 - -0.16.4 -====== -66b8bfd Adding release tag REL_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 - -0.16.3 -====== -ab17248 Adding release tag REL_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 @@ -4975,17 +5107,9 @@ a1574a5 Fixing TransObject#to_type so that it does not modify the object being 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. - -0.16.2 -====== -13c91ea Adding release tag REL_0_16_2 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. - -0.16.1 -====== -77bf69c Adding release tag REL_0_16_1 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. @@ -4993,10 +5117,6 @@ baa412c Adding "defined" functino to puppet, so you can now test whether a give 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 - -0.16.0 -====== -2492328 Adding release tag REL_0_16_0 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. @@ -5034,10 +5154,6 @@ ae4b12e Revamp the yumrepo type to deal with repositories defined anywhere in y 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 - -0.15.3 -====== -abf09dc Adding release tag REL_0_15_3 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. @@ -5047,10 +5163,6 @@ fcce820 Okay, last one, hopefully. Modifying checks to support arrays. 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 - -0.15.2 -====== -feab8d9 Adding release tag REL_0_15_2 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 @@ -5094,10 +5206,6 @@ a9fdf9d Disbale running puppetmaster as puppet until we've sorted out which fil 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 - -0.15.1 -====== -437ee64 Adding release tag REL_0_15_1 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. @@ -5113,10 +5221,6 @@ fc68910 removing dos EOL chars 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 - -0.15.0 -====== -1409cd6 Adding release tag REL_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. @@ -5146,19 +5250,11 @@ b6d829b Fixing #95. I had to redesign how events were triggered; the transacti 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 - -0.14.1 -====== -ad0fa4b Adding release tag REL_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 - -0.14.0 -====== -783735c Adding release tag REL_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. @@ -5175,10 +5271,6 @@ f2ea9b7 Supporting variables as the test value in both case statements and sele 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 - -0.13.6 -====== -25614df Adding release tag REL_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. @@ -5207,20 +5299,12 @@ b119a72 Fixing output when user/group are not found 043fc33 adding commas to each line d06cd3f removing the initial syslog dest setting f6ca82b Updated to version 0.13.5 - -0.13.5 -====== -7ec2f82 Adding release tag REL_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 - -0.13.4 -====== -d0b3f6c Adding release tag REL_0_13_4 1f05ad0 updating changelog for 0.13.4 cfb0e36 updates 89856ec Adding a bit more logging @@ -5237,10 +5321,6 @@ beef01c Properly figure out when updates are available. Previously, packages wo 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 - -0.13.2 -====== -d0bbab5 Adding release tag REL_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. @@ -5255,10 +5335,6 @@ f098485 Correcting some path problems with symlink, and changing "target" state 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 - -0.13.1 -====== -ac8f3ae Adding release tag REL_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. @@ -5269,10 +5345,6 @@ 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 - -0.13.0 -====== -4751fce Adding release tag REL_0_13_0 2cb5cb3 Updating changelog for 0.13.0 387db24 Adding answerfile support to sun pkgs. 2ce061a adding some documentation @@ -5309,10 +5381,6 @@ d5af359 Rewrote client init script since puppetd is now a proper demon. 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 - -0.12.0 -====== -2c35151 Adding 0.12.0 release tag 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 @@ -5322,26 +5390,14 @@ ae2575b Adding the event-loop stuff to the repository and switching to using it 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 - -0.11.2 -====== -36f6e05 Adding release tag REL_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 - -0.11.1 -====== -4bbb952 Adding release tag REL_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 - -0.11.0 -====== -1d2095b Adding release tag REL_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 @@ -5362,10 +5418,6 @@ f420135 Converting transport format to YAML instead of Marshal, and caching the 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 - -0.10.2 -====== -f7211e3 Adding release tag REL_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 @@ -5374,10 +5426,6 @@ f7211e3 Adding release tag REL_0_10_2 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 - -0.10.1 -====== -dc012b1 adding 0.10.1 release tag 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 @@ -5386,10 +5434,6 @@ dc012b1 adding 0.10.1 release tag 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 - -0.10.0 -====== -8458a0d Adding 0.10.0 release tag 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 @@ -5409,10 +5453,6 @@ 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 - -0.9.3 -===== -d4a9f3e Adding release tag 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 @@ -1,6 +1,6 @@ -Puppet - Automating Configuration Management. Copyright (C) 2005 Reductive Labs LLC +Puppet - Automating Configuration Management. Copyright (C) 2005 Puppet Labs LLC -Reductive Labs can be contacted at: info@reductivelabs.com +Puppet Labs can be contacted at: info@puppetlabs.com This program and entire repository is free software; you can redistribute it and/or modify it under the terms of the GNU @@ -43,7 +43,7 @@ desc "Create the tarball and the gem - use when releasing" task :puppetpackages => [:create_gem, :package] Spec::Rake::SpecTask.new do |t| - t.spec_opts = ['--format','s', '--loadby','mtime','--color'] + t.spec_opts = ['--format','s', '--loadby','mtime','--color', '--backtrace'] t.pattern ='spec/{unit,integration}/**/*.rb' t.fail_on_error = false end diff --git a/conf/redhat/puppet.spec b/conf/redhat/puppet.spec index 6791cea77..e51af0a6b 100644 --- a/conf/redhat/puppet.spec +++ b/conf/redhat/puppet.spec @@ -5,14 +5,14 @@ %global confdir conf/redhat Name: puppet -Version: 0.25.5 +Version: 2.6.0 Release: 1%{?dist} Summary: A network tool for managing many disparate systems License: GPLv2+ URL: http://puppetlabs.com Source0: http://puppetlabs.com/downloads/%{name}/%{name}-%{version}.tar.gz Source1: http://puppetlabs.com/downloads/%{name}/%{name}-%{version}.tar.gz.sign -Patch0: rundir-perms.patch + Group: System Environment/Base BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -68,6 +68,7 @@ The server can also function as a certificate authority and file server. %setup -q patch -p1 < conf/redhat/rundir-perms.patch + %build # Fix some rpmlint complaints for f in mac_dscl.pp mac_dscl_revert.pp \ @@ -91,6 +92,7 @@ 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 @@ -221,6 +223,10 @@ fi rm -rf %{buildroot} %changelog +* Tue Jul 20 2010 Todd Zullinger <tmz@pobox.com> - 2.6.0-1 +- Update to 2.6.0 +- Create and own /usr/share/puppet/modules (#615432) + * Mon May 03 2010 Todd Zullinger <tmz@pobox.com> - 0.25.5-1 - Update to 0.25.5 - Adjust selinux conditional for EL-6 diff --git a/conf/solaris/smf/svc-puppetd b/conf/solaris/smf/svc-puppetd index 9036b505c..b6cf05736 100755 --- a/conf/solaris/smf/svc-puppetd +++ b/conf/solaris/smf/svc-puppetd @@ -12,7 +12,7 @@ exec_prefix=/opt/csw sysconfdir=/opt/csw/etc sbindir=/opt/csw/sbin -pidfile=/var/lib/puppet/run/puppetd.pid +pidfile=/var/lib/puppet/run/agent.pid case "$1" in start) diff --git a/conf/solaris/smf/svc-puppetmasterd b/conf/solaris/smf/svc-puppetmasterd index 34f5a62e6..80e3d464a 100755 --- a/conf/solaris/smf/svc-puppetmasterd +++ b/conf/solaris/smf/svc-puppetmasterd @@ -8,7 +8,7 @@ exec_prefix=/opt/csw sysconfdir=/opt/csw/etc sbindir=/opt/csw/sbin -pidfile=/var/lib/puppet/run/puppetmasterd.pid +pidfile=/var/lib/puppet/run/master.pid case "$1" in start) diff --git a/conf/suse/client.init b/conf/suse/client.init index d72b09b2c..71585cd7b 100644 --- a/conf/suse/client.init +++ b/conf/suse/client.init @@ -13,10 +13,10 @@ ### BEGIN INIT INFO # Provides: puppet -# Required-Start: $local_fs $network $syslog -# Should-Start: $null -# Required-Stop: $null -# Should-Stop: $null +# Required-Start: $local_fs $remote_fs $network $syslog +# Should-Start: puppet +# Required-Stop: $local_fs $remote_fs $network $syslog +# Should-Stop: puppet # Default-Start: 3 4 5 # Default-Stop: 0 1 2 6 # Short-Description: puppet diff --git a/conf/suse/fileserver.conf b/conf/suse/fileserver.conf new file mode 100644 index 000000000..67e387ca0 --- /dev/null +++ b/conf/suse/fileserver.conf @@ -0,0 +1,12 @@ +# This file consists of arbitrarily named sections/modules +# defining where files are served from and to whom + +# Define a section 'files' +# Adapt the allow/deny settings to your needs. Order +# for allow/deny does not matter, allow always takes precedence +# over deny +# [files] +# path /var/lib/puppet/files +# allow *.example.com +# deny *.evil.example.com +# allow 192.168.0.0/24 diff --git a/conf/suse/logrotate b/conf/suse/logrotate new file mode 100644 index 000000000..c3a4d437a --- /dev/null +++ b/conf/suse/logrotate @@ -0,0 +1,10 @@ +/var/log/puppet/*log { + missingok + notifempty + create 0644 puppet puppet + sharedscripts + postrotate + [ -e /etc/init.d/puppetmaster ] && /etc/init.d/puppetmaster condrestart >/dev/null 2>&1 || true + [ -e /etc/init.d/puppet ] && /etc/init.d/puppet reload > /dev/null 2>&1 || true + endscript +} diff --git a/conf/suse/puppet.conf b/conf/suse/puppet.conf new file mode 100644 index 000000000..47501a388 --- /dev/null +++ b/conf/suse/puppet.conf @@ -0,0 +1,25 @@ +[main] + # The Puppet log directory. + # The default value is '$vardir/log'. + logdir = /var/log/puppet + + # Where Puppet PID files are kept. + # The default value is '$vardir/run'. + rundir = /var/run/puppet + + # Where SSL certificates are kept. + # The default value is '$confdir/ssl'. + ssldir = $vardir/ssl + +[agent] + # The file in which puppetd stores a list of the classes + # associated with the retrieved configuratiion. Can be loaded in + # the separate ``puppet`` executable using the ``--loadclasses`` + # option. + # The default value is '$confdir/classes.txt'. + classfile = $vardir/classes.txt + + # Where puppetd caches the local configuration. An + # extension indicating the cache format is added automatically. + # The default value is '$confdir/localconfig'. + localconfig = $vardir/localconfig diff --git a/conf/suse/puppet.spec b/conf/suse/puppet.spec index 2a0e6e359..777f6a4b6 100644 --- a/conf/suse/puppet.spec +++ b/conf/suse/puppet.spec @@ -1,31 +1,32 @@ %{!?ruby_sitelibdir: %define ruby_sitelibdir %(ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"]')} %define pbuild %{_builddir}/%{name}-%{version} -%define suseconfdir conf/suse -%define confdir conf/redhat +%define confdir conf/suse Summary: A network tool for managing many disparate systems Name: puppet -Version: 0.25.4 +Version: 2.6.1 Release: 1%{?dist} License: GPL -Group: System Environment/Base +Group: Productivity/Networking/System -URL: http://reductivelabs.com/projects/puppet/ -Source: http://reductivelabs.com/downloads/puppet/%{name}-%{version}.tar.gz -Patch0: puppet.suse.patch +URL: http://puppetlabs.com/projects/puppet/ +Source0: http://puppetlabs.com/downloads/puppet/%{name}-%{version}.tar.gz + +PreReq: %{insserv_prereq} %{fillup_prereq} Requires: ruby >= 1.8.2 -Requires: facter >= 1.3.7 +Requires: facter >= 1.5 +Requires: cron BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: ruby >= 1.8.2 %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, +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 +Group: Productivity/Networking/System Summary: Server for the puppet system management tool Requires: puppet = %{version}-%{release} @@ -35,55 +36,56 @@ The server can also function as a certificate authority and file server. %prep %setup -q -%patch0 -p0 %build -for f in bin/* ; do - sed -i -e '1c#!/usr/bin/ruby' $f +for f in bin/* sbin/*; do + sed -i -e '1s,^#!.*ruby$,#!/usr/bin/ruby,' $f done %install %{__install} -d -m0755 %{buildroot}%{_sbindir} %{__install} -d -m0755 %{buildroot}%{_bindir} +%{__install} -d -m0755 %{buildroot}%{_confdir} %{__install} -d -m0755 %{buildroot}%{ruby_sitelibdir} %{__install} -d -m0755 %{buildroot}%{_sysconfdir}/puppet/manifests %{__install} -d -m0755 %{buildroot}%{_docdir}/%{name}-%{version} %{__install} -d -m0755 %{buildroot}%{_localstatedir}/lib/puppet %{__install} -d -m0755 %{buildroot}%{_localstatedir}/run/puppet %{__install} -d -m0755 %{buildroot}%{_localstatedir}/log/puppet -%{__install} -Dp -m0755 %{pbuild}/bin/* %{buildroot}%{_sbindir} +%{__install} -Dp -m0755 %{pbuild}/bin/* %{buildroot}%{_bindir} %{__install} -Dp -m0755 %{pbuild}/sbin/* %{buildroot}%{_sbindir} -%{__mv} %{buildroot}%{_sbindir}/puppet %{buildroot}%{_bindir}/puppet -%{__mv} %{buildroot}%{_sbindir}/puppetrun %{buildroot}%{_bindir}/puppetrun %{__install} -Dp -m0644 %{pbuild}/lib/puppet.rb %{buildroot}%{ruby_sitelibdir}/puppet.rb %{__cp} -a %{pbuild}/lib/puppet %{buildroot}%{ruby_sitelibdir} find %{buildroot}%{ruby_sitelibdir} -type f -perm +ugo+x -exec chmod a-x '{}' \; -%{__install} -Dp -m0644 %{confdir}/client.sysconfig %{buildroot}/var/adm/fillup-templates/sysconfig.puppet -%{__install} -Dp -m0755 %SOURCE1 %{buildroot}%{_initrddir}/puppet -%{__install} -Dp -m0644 %{confdir}/server.sysconfig %{buildroot}/var/adm/fillup-templates/sysconfig.puppetmaster -%{__install} -Dp -m0755 %SOURCE2 %{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 -#%{__ln_s} puppet.conf %{buildroot}%{_sysconfdir}/puppet/puppetmasterd.conf -#%{__ln_s} puppet.conf %{buildroot}%{_sysconfdir}/puppet/puppetca.conf -%{__install} -Dp -m0644 %{confdir}/logrotate %{buildroot}%{_sysconfdir}/logrotate.d/puppet +%{__cp} -a %{pbuild}/conf/redhat/client.sysconfig %{buildroot}%{_confdir}/client.sysconfig +%{__install} -Dp -m0644 %{buildroot}%{_confdir}/client.sysconfig %{buildroot}/var/adm/fillup-templates/sysconfig.puppet +%{__cp} -a %{pbuild}/conf/redhat/server.sysconfig %{buildroot}%{_confdir}/server.sysconfig +%{__install} -Dp -m0644 %{buildroot}%{_confdir}/server.sysconfig %{buildroot}/var/adm/fillup-templates/sysconfig.puppetmaster +%{__cp} -a %{pbuild}/conf/redhat/fileserver.conf %{buildroot}%{_confdir}/fileserver.conf +%{__install} -Dp -m0644 %{buildroot}%{_confdir}/fileserver.conf %{buildroot}%{_sysconfdir}/puppet/fileserver.conf +%{__cp} -a %{pbuild}/conf/redhat/puppet.conf %{buildroot}%{_confdir}/puppet.conf +%{__install} -Dp -m0644 %{buildroot}%{_confdir}/puppet.conf %{buildroot}%{_sysconfdir}/puppet/puppet.conf +%{__cp} -a %{pbuild}/conf/redhat/logrotate %{buildroot}%{_confdir}/logrotate +%{__install} -Dp -m0644 %{buildroot}%{_confdir}/logrotate %{buildroot}%{_sysconfdir}/logrotate.d/puppet +%{__install} -Dp -m0755 %{confdir}/client.init %{buildroot}%{_initrddir}/puppet +%{__install} -Dp -m0755 %{confdir}/server.init %{buildroot}%{_initrddir}/puppetmaster %{__ln_s} %{_initrddir}/puppet %{buildroot}%{_sbindir}/rcpuppet %{__ln_s} %{_initrddir}/puppetmaster %{buildroot}%{_sbindir}/rcpuppetmaster %files %defattr(-, root, root, 0755) %{_bindir}/puppet -%{_sbindir}/filebucket -%{_sbindir}/ralsh +%{_bindir}/puppetdoc +%{_bindir}/filebucket +%{_bindir}/ralsh +%{_bindir}/pi %{_sbindir}/puppetd %{_sbindir}/rcpuppet -%{_sbindir}/pi %{ruby_sitelibdir}/* %{_initrddir}/puppet /var/adm/fillup-templates/sysconfig.puppet %config(noreplace) %{_sysconfdir}/puppet/puppet.conf %doc CHANGELOG COPYING LICENSE README examples -%exclude %{_sbindir}/puppetdoc %config(noreplace) %{_sysconfdir}/logrotate.d/puppet %dir %{_sysconfdir}/puppet # These need to be owned by puppet so the server can @@ -95,56 +97,122 @@ find %{buildroot}%{ruby_sitelibdir} -type f -perm +ugo+x -exec chmod a-x '{}' \; %files server %defattr(-, root, root, 0755) %{_sbindir}/puppetmasterd +%{_sbindir}/rcpuppetmaster %{_sbindir}/puppetqd -%{_bindir}/puppetrun +%{_sbindir}/puppetrun +%{_sbindir}/puppetca %{_initrddir}/puppetmaster %config(noreplace) %{_sysconfdir}/puppet/* -%config(noreplace) %{_sysconfdir}/sysconfig/puppetmaster -%{_sbindir}/puppetca +%exclude %{_sysconfdir}/puppet/puppet.conf +/var/adm/fillup-templates/sysconfig.puppetmaster +%dir %{_sysconfdir}/puppet %pre /usr/sbin/groupadd -r puppet 2>/dev/null || : /usr/sbin/useradd -g puppet -c "Puppet" \ - -s /sbin/nologin -r -d /var/lib/puppet puppet 2> /dev/null || : + -s /sbin/nologin -r -d /var/puppet puppet 2> /dev/null || : %post -/sbin/chkconfig --add puppet -exit 0 +%{fillup_and_insserv -y puppet} %post server -/sbin/chkconfig --add puppetmaster +%{fillup_and_insserv -n -y puppetmaster} %preun -if [ "$1" = 0 ] ; then - /sbin/service puppet stop > /dev/null 2>&1 - /sbin/chkconfig --del puppet -fi +%stop_on_removal puppet %preun server -if [ "$1" = 0 ] ; then - /sbin/service puppetmaster stop > /dev/null 2>&1 - /sbin/chkconfig --del puppetmaster -fi +%stop_on_removal puppetmaster + +%postun +%restart_on_update puppet +%{insserv_cleanup} %postun server -if [ "$1" -ge 1 ]; then - /sbin/service puppetmaster try-restart > /dev/null 2>&1 -fi +%restart_on_update puppetmaster +%{insserv_cleanup} %clean %{__rm} -rf %{buildroot} %changelog -* Sat Feb 16 2008 James Turnbull <james@lovedthanlost.net> - 0.24.1-1 -- Fixed puppet configuation file references to match single puppet.conf file -- Update versions for 0.24.1 release +* Tue Sep 14 2010 Ben Kevan <ben.kevan@gmail.com> - 2.6.1 +- New version to 2.6.1 +- Add client.init and server.init from source since it's now included in the packages +- Change BuildRequires Ruby version to match Requires Ruby version +- Removed ruby-env patch, replaced with sed in prep +- Update urls to puppetlabs.com + +* Wed Jul 21 2010 Ben Kevan <ben.kevan@gmail.com> - 2.6.0 +- New version and ruby version bump +- Add puppetdoc to %_bindir (unknown why original suse package, excluded or forgot to add) +- Corrected patch for ruby environment +- Move binaries back to the correct directories + +* Wed Jul 14 2010 Ben Kevan <ben.kevan@gmail.com> - 0.25.5 +- New version. +- Use original client, server.init names +- Revert to puppetmaster +- Fixed client.init and server.init and included $null and Should-Stop for both + +* Tue Mar 2 2010 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.25.4 +- New version. + +* Sun Aug 9 2009 Noah Fontes <nfontes@transtruct.org> +- Fix build on SLES 9. +- Enable puppet and puppet-server services by default. + +* Sat Aug 8 2009 Noah Fontes <nfontes@transtruct.org> +- Fix a lot of relevant warnings from rpmlint. +- Build on OpenSUSE 11.1 correctly. +- Rename puppetmaster init scripts to puppet-server to correspond to the package name. + +* Wed Apr 22 2009 Leo Eraly <leo@unstable.be> - 0.24.8 +- New version. + +* Tue Dec 9 2008 Leo Eraly <leo@unstable.be> - 0.24.6 +- New version. + +* Fri Sep 5 2008 Leo Eraly <leo@unstable.be> - 0.24.5 +- New version. + +* Fri Jun 20 2008 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.24.4 +- Removed symlinks to old configuration files + +* Fri Dec 14 2007 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.24.0 +- New version. + +* Fri Jun 29 2007 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.23.0 +- New version. + +* Wed May 2 2007 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.22.4 +- New version. Includes provider for rug package manager. + +* Wed Apr 25 2007 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.22.3 +- New version. Added links /sbin/rcpuppet and /sbin/rcpuppetmaster + +* Sun Jan 7 2007 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.22.0 +- version bump + +* Tue Oct 3 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.19.3-3 +- Made package arch dependant. + +* Sat Sep 23 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.19.3-1 +- New version + +* Sun Sep 17 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.19.1-1 +- New version + +* Tue Aug 30 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.19.0-1 +- New version +- No need to patch anymore :-), since my changes went into official release. * Tue Aug 3 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.18.4-3 - Replaced puppet-bin.patch with %build section from David's spec * Tue Aug 1 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.18.4-2 - Added supprot for enabling services in SuSE - + * Tue Aug 1 2006 Martin Vuk <martin.vuk@fri.uni-lj.si> - 0.18.4-1 - New version and support for SuSE diff --git a/conf/suse/puppet.suse.patch b/conf/suse/puppet.suse.patch deleted file mode 100644 index 41974679f..000000000 --- a/conf/suse/puppet.suse.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- sbin/puppetmasterd.orig 2009-11-23 10:38:16.632264990 -0500 -+++ sbin/puppetmasterd 2009-11-23 10:38:28.884265155 -0500 -@@ -1,4 +1,4 @@ --#!/usr/bin/env ruby -+#!/usr/bin/ruby - - # - # = Synopsis ---- sbin/puppetd.orig 2009-11-23 10:38:23.240265893 -0500 -+++ sbin/puppetd 2009-11-23 10:38:35.044265271 -0500 -@@ -1,4 +1,4 @@ --#!/usr/bin/env ruby -+#!/usr/bin/ruby - # == Synopsis - # - # Retrieve the client configuration from the central puppet server and apply diff --git a/conf/suse/server.init b/conf/suse/server.init index e3a1d902a..50b9fef81 100644 --- a/conf/suse/server.init +++ b/conf/suse/server.init @@ -11,10 +11,10 @@ ### BEGIN INIT INFO # Provides: puppetmaster -# Required-Start: $local_fs $network $syslog -# Should-Start: $null -# Required-Stop: $null -# Should-Stop: $null +# Required-Start: $local_fs $remote_fs $network $syslog +# Should-Start: puppetmaster +# Required-Stop: $local_fs $remote_fs $network $syslog +# Should-Stop: puppetmaster # Default-Start: 3 4 5 # Default-Stop: 0 1 2 6 # Short-Description: puppetmaster diff --git a/ext/cert_inspector b/ext/cert_inspector new file mode 100755 index 000000000..1effcaa04 --- /dev/null +++ b/ext/cert_inspector @@ -0,0 +1,140 @@ +#!/usr/bin/env ruby +require 'openssl' + +class X509Collector + include Enumerable + + def initialize + @collected_data = {} + end + + def interpret_contents(contents) + cls = case contents.split("\n")[0] + when /BEGIN X509 CRL/ then OpenSSL::X509::CRL + when /BEGIN CERTIFICATE REQUEST/ then OpenSSL::X509::Request + when /BEGIN CERTIFICATE/ then OpenSSL::X509::Certificate + when /BEGIN RSA (PRIVATE|PUBLIC) KEY/ then OpenSSL::PKey::RSA + else return nil + end + cls.new(contents) + rescue + nil + end + + def expected_non_x509_files + ['inventory.txt', 'ca.pass', 'serial'] + end + + def investigate_path(path) + if File.directory?(path) + Dir.foreach(path) do |x| + next if ['.', '..'].include? x + investigate_path File.join(path, x) + end + else + contents = File.read path + meaning = interpret_contents contents + unless meaning || expected_non_x509_files.include?(File.basename(path)) + puts "WARNING: file #{path.inspect} could not be interpreted" + end + @collected_data[path] = meaning if meaning + end + end + + def each(&block) + @collected_data.each(&block) + end + + def extract_public_key_info(path, meaning) + case meaning + when OpenSSL::PKey::RSA + if meaning.private? + [meaning.public_key, 2, path] + else + [meaning, 3, path] + end + when OpenSSL::X509::Certificate + [meaning.public_key, 0, meaning.subject.to_s] + when OpenSSL::X509::Request + [meaning.public_key, 1, meaning.subject.to_s] + end + end + + def who_signed(meaning, key_names, keys) + signing_key = keys.find { |key| meaning.verify(key) } + if signing_key then "#{key_names[signing_key.to_s]}" else "???" end + end + + def explain(meaning, key_names, keys) + case meaning + when OpenSSL::PKey::RSA + if meaning.private? + "Private key for #{key_names[meaning.public_key.to_s]}" + else + "Public key for #{key_names[meaning.public_key.to_s]}" + end + when OpenSSL::X509::Certificate + signature_desc = who_signed(meaning, key_names, keys) + "Certificate assigning name #{meaning.subject.to_s} to #{key_names[meaning.public_key.to_s]}\n serial number #{meaning.serial}\n issued by #{meaning.issuer.to_s}\n signed by #{signature_desc}" + when OpenSSL::X509::Request + signature_desc = who_signed(meaning, key_names, keys) + "Certificate request for #{meaning.subject.to_s} having key #{key_names[meaning.public_key.to_s]}\n signed by #{signature_desc}" + when OpenSSL::X509::CRL + signature_desc = who_signed(meaning, key_names, keys) + revoked_serial_numbers = meaning.revoked.map { |r| r.serial } + revoked_desc = if revoked_serial_numbers.count > 0 then "serial numbers #{revoked_serial_numbers.inspect}" else "nothing" end + "Certificate revocation list revoking #{revoked_desc}\n issued by #{meaning.issuer.to_s}\n signed by #{signature_desc}" + else + "Unknown" + end + end + + # Yield unique public keys, with a canonical name for each. + def collect_public_keys + key_data = {} # pem => (priority, name, public_key) + @collected_data.collect do |path, meaning| + begin + next unless public_key_info = extract_public_key_info(path, meaning) + public_key, priority, name = public_key_info + pem = public_key.to_s + existing_priority, existing_name, existing_public_key = key_data[pem] + next if existing_priority and existing_priority < priority + key_data[pem] = priority, name, public_key + rescue + puts "exception!" + end + end + name_to_key_hash = {} + key_data.each do |pem, data| + priority, name, public_key = data + if name_to_key_hash[name] + suffix_num = 2 + while name_to_key_hash[name + " (#{suffix_num})"] + suffix_num += 1 + end + name = name + " (#{suffix_num})" + end + name_to_key_hash[name] = public_key + end + key_names = {} + keys = [] + name_to_key_hash.each do |name, public_key| + key_names[public_key.to_s] = "key<#{name}>" + keys << public_key + end + [key_names, keys] + end +end + +collector = X509Collector.new +ARGV.each do |path| + collector.investigate_path(path) +end +key_names, keys = collector.collect_public_keys +collector.map do |path, meaning| + [collector.explain(meaning, key_names, keys), path] +end.sort.each do |description, path| + puts "#{path}:" + puts " #{description}" + puts +end diff --git a/ext/envpuppet b/ext/envpuppet new file mode 100755 index 000000000..d921a19b8 --- /dev/null +++ b/ext/envpuppet @@ -0,0 +1,80 @@ +#! /bin/bash +# +# Jeff McCune <jeff@puppetlabs.com> +# 2010-10-20 +# +# Copyright (c) 2010, Puppet Labs +# License: BSD 3-clause license +# +# This script provides a simple way to execute puppet and related tools +# directly from a git clone of the upstream repositories. This allows you to +# quickly switch branches and test different versions of code without much +# friction. +# +# NOTE: There may be issues if puppet, facter, etc... are already installed +# into RUBY's site_ruby directory. If you run into strange problems, make sure +# the correct ruby libraries are being loaded... +# +# Sample Usage: +# ============= +# cd ~/src +# git clone git://github.com/puppetlabs/puppet.git +# git clone git://github.com/puppetlabs/facter.git +# pushd puppet +# git checkout tags/2.6.1 +# popd +# pushd facter +# git checkout tags/1.5.8 +# export ENVPUPPET_BASEDIR=/home/jeff/src +# envpuppet puppet --version +# 2.6.1 +# envpuppet facter --version +# 1.5.8 + +set -e +set -u + +if test -d puppet -o -d facter; then + echo " WARNING!" + echo " Strange things happen if puppet or facter are in the" + echo " current working directory" + echo " (import errors from ruby are a prime example)" + echo " WARNING!" + echo "" + echo "I suggest changing to ~ or /tmp or something..." + echo "" + echo "Sleeping 2 seconds." + echo "" + sleep 2 +fi + +# Set this to where you check out puppet and facter +: ${ENVPUPPET_BASEDIR:="${HOME}/src"} + +# git://github.com/reductivelabs/puppet.git +mypath="${ENVPUPPET_BASEDIR}/puppet/sbin:${ENVPUPPET_BASEDIR}/puppet/bin" +myrubylib="${ENVPUPPET_BASEDIR}/puppet/lib" + +# git://github.com/reductivelabs/facter.git +mypath="${mypath}:${ENVPUPPET_BASEDIR}/facter/bin" +myrubylib="${myrubylib}:${ENVPUPPET_BASEDIR}/facter/lib" + +# http://github.com/jamtur01/puppet-scaffold.git +mypath="${mypath}:${ENVPUPPET_BASEDIR}/puppet-scaffold/bin" +myrubylib="${myrubylib}:${ENVPUPPET_BASEDIR}/puppet-scaffold/lib" + +# http://github.com/puppetlabs/puppet-module-tool.git +# Also known as "pmt" Will become "puppet module" +mypath="${mypath}:${ENVPUPPET_BASEDIR}/puppet-module-tool/bin" +myrubylib="${myrubylib}:${ENVPUPPET_BASEDIR}/puppet-module-tool/lib" + +# Use the existing environment, if present. +# Default to no value to prevent unbound variable issues +mypath="${mypath}:${PATH:-}" +myrubylib="${myrubylib}:${RUBYLIB:-}" + +# Trim any trailing colons from the path list. +export PATH="${mypath%%:}" +export RUBYLIB="${myrubylib%%:}" + +exec "$@" diff --git a/ext/extlookup.rb b/ext/extlookup.rb deleted file mode 100644 index d87583ba7..000000000 --- a/ext/extlookup.rb +++ /dev/null @@ -1,181 +0,0 @@ -# Puppet External Data Sources -# -# This is a parser function to read data from external files, this version -# uses CSV files but the concept can easily be adjust for databases, yaml -# or any other queryable data source. -# -# The object of this is to make it obvious when it's being used, rather than -# magically loading data in when an module is loaded I prefer to look at the code -# and see statements like: -# -# $snmp_contact = extlookup("snmp_contact") -# -# The above snippet will load the snmp_contact value from CSV files, this in its -# own is useful but a common construct in puppet manifests is something like this: -# -# case $domain { -# "myclient.com": { $snmp_contact = "John Doe <john@myclient.com>" } -# default: { $snmp_contact = "My Support <support@my.com>" } -# } -# -# Over time there will be a lot of this kind of thing spread all over your manifests -# and adding an additional client involves grepping through manifests to find all the -# places where you have constructs like this. -# -# This is a data problem and shouldn't be handled in code, a using this function you -# can do just that. -# -# First you configure it in site.pp: -# $extlookup_datadir = "/etc/puppet/manifests/extdata" -# $extlookup_precedence = ["%{fqdn}", "domain_%{domain}", "common"] -# -# The array tells the code how to resolve values, first it will try to find it in -# web1.myclient.com.csv then in domain_myclient.com.csv and finally in common.csv -# -# Now create the following data files in /etc/puppet/manifests/extdata -# -# domain_myclient.com.csv: -# snmp_contact,John Doe <john@myclient.com> -# root_contact,support@%{domain} -# client_trusted_ips,192.168.1.130,192.168.10.0/24 -# -# common.csv: -# snmp_contact,My Support <support@my.com> -# root_contact,support@my.com -# -# Now you can replace the case statement with the simple single line to achieve -# the exact same outcome: -# -# $snmp_contact = extlookup("snmp_contact") -# -# The obove code shows some other features, you can use any fact or variable that -# is in scope by simply using %{varname} in your data files, you can return arrays -# by just having multiple values in the csv after the initial variable name. -# -# In the event that a variable is nowhere to be found a critical error will be raised -# that will prevent your manifest from compiling, this is to avoid accidentally putting -# in empty values etc. You can however specify a default value: -# -# $ntp_servers = extlookup("ntp_servers", "1.${country}.pool.ntp.org") -# -# In this case it will default to "1.${country}.pool.ntp.org" if nothing is defined in -# any data file. -# -# You can also specify an additional data file to search first before any others at use -# time, for example: -# -# $version = extlookup("rsyslog_version", "present", "packages") -# -# package{"rsyslog": ensure => $version } -# -# This will look for a version configured in packages.csv and then in the rest as configured -# by $extlookup_precedence if it's not found anywhere it will default to "present", this kind -# of use case makes puppet a lot nicer for managing large amounts of packages since you do not -# need to edit a load of manifests to do simple things like adjust a desired version number. -# -# For more information on installing and writing your own custom functions see: -# http://docs.puppetlabs.com/guides/custom_functions.html -# -# For further help contact Volcane on #puppet -require 'csv' - -module Puppet::Parser::Functions - newfunction(:extlookup, :type => :rvalue) do |args| - key = args[0] - default = "_ExtUNSET_" - datafile = "_ExtUNSET_" - - default = args[1] if args[1] - datafile = args[2] if args[2] - - extlookup_datadir = lookupvar('extlookup_datadir') - extlookup_precedence = Array.new - - # precedence values can have variables embedded in them - # in the form %{fqdn}, you could for example do - # - # $extlookup_precedence = ["hosts/%{fqdn}", "common"] - # - # this will result in /path/to/extdata/hosts/your.box.com.csv - # being searched. - # - # we parse the precedence here because the best place to specify - # it would be in site.pp but site.pp is only evaluated at startup - # so $fqdn etc would have no meaning there, this way it gets evaluated - # each run and has access to the right variables for that run - lookupvar('extlookup_precedence').each do |prec| - while prec =~ /%\{(.+?)\}/ - prec.gsub!(/%\{#{$1}\}/, lookupvar($1)) - end - - extlookup_precedence << prec - end - - - datafiles = Array.new - - # if we got a custom data file, put it first in the array of search files - if datafile != "" - datafiles << extlookup_datadir + "/#{datafile}.csv" if File.exists?(extlookup_datadir + "/#{datafile}.csv") - end - - extlookup_precedence.each do |d| - datafiles << extlookup_datadir + "/#{d}.csv" - end - - desired = "_ExtUNSET_" - - datafiles.each do |file| - parser.watch_file(file) if File.exists?(file) - - if desired == "_ExtUNSET_" - if File.exists?(file) - result = CSV.read(file).find_all do |r| - r[0] == key - end - - - # return just the single result if theres just one, - # else take all the fields in the csv and build an array - if result.length > 0 - if result[0].length == 2 - val = result[0][1].to_s - - # parse %{}'s in the CSV into local variables using lookupvar() - while val =~ /%\{(.+?)\}/ - val.gsub!(/%\{#{$1}\}/, lookupvar($1)) - end - - desired = val - elsif result[0].length > 1 - length = result[0].length - cells = result[0][1,length] - - # Individual cells in a CSV result are a weird data type and throws - # puppets yaml parsing, so just map it all to plain old strings - desired = cells.map do |c| - # parse %{}'s in the CSV into local variables using lookupvar() - while c =~ /%\{(.+?)\}/ - c.gsub!(/%\{#{$1}\}/, lookupvar($1)) - end - - c.to_s - end - end - end - end - end - end - - # don't accidently return nil's and such rather throw a parse error - if desired == "_ExtUNSET_" && default == "_ExtUNSET_" - raise Puppet::ParseError, "No match found for '#{key}' in any data file during extlookup()" - else - desired = default if desired == "_ExtUNSET_" - end - - desired - end -end - -# vi:tabstop=4:expandtab:ai diff --git a/ext/logcheck/puppet b/ext/logcheck/puppet index f3280c7b7..7de06aa0f 100644 --- a/ext/logcheck/puppet +++ b/ext/logcheck/puppet @@ -1,23 +1,23 @@ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetmasterd\[[0-9]+\]: (Handled resources in|Resource comparison took|Searched for (host|resources|resource params and tags) in) [0-9.]+ seconds -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetmasterd\[[0-9]+\]: Starting Puppet server version [.0-9]+$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetmasterd\[[0-9]+\]: Compiled catalog for [._[:alnum:]-]+ in [.0-9]+ seconds$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetmasterd\[[0-9]+\]: Caught TERM; shutting down$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetmasterd\[[0-9]+\]: Shutting down$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Starting Puppet client version [.0-9]+$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: getting config$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Caching configuration at [\/._[:alnum:]-]+$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Loaded state in [.0-9]+ seconds$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Calling puppetmaster.getconfig$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Retrieved configuration in [.0-9]+ seconds$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Starting configuration run$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Finished configuration run in [.0-9]+ seconds$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Caught (TERM|INT); shutting down$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Shutting down$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Restarting with .*$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Starting catalog run$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Finished catalog run in [.0-9]+ seconds$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Loading fact .*$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Ignoring cache$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Ignoring --listen on onetime run$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetd\[[0-9]+\]: Retrieving plugins$ -^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppetmasterd\[[0-9]+\]: Reopening log files$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: (Handled resources in|Resource comparison took|Searched for (host|resources|resource params and tags) in) [0-9.]+ seconds +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Starting Puppet server version [.0-9]+$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Compiled catalog for [._[:alnum:]-]+ in [.0-9]+ seconds$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Caught TERM; shutting down$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Shutting down$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Starting Puppet client version [.0-9]+$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: getting config$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Caching configuration at [\/._[:alnum:]-]+$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Loaded state in [.0-9]+ seconds$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Calling puppetmaster.getconfig$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Retrieved configuration in [.0-9]+ seconds$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Starting configuration run$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Finished configuration run in [.0-9]+ seconds$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Caught (TERM|INT); shutting down$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Shutting down$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Restarting with .*$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Starting catalog run$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Finished catalog run in [.0-9]+ seconds$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Loading fact .*$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Ignoring cache$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Ignoring --listen on onetime run$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-agent\[[0-9]+\]: Retrieving plugins$ +^\w{3} [ :0-9]{11} [._[:alnum:]-]+ puppet-master\[[0-9]+\]: Reopening log files$ diff --git a/ext/puppet-load.rb b/ext/puppet-load.rb new file mode 100644 index 000000000..35bee6ef8 --- /dev/null +++ b/ext/puppet-load.rb @@ -0,0 +1,393 @@ +#!/usr/bin/env ruby +# == Synopsis +# +# This tool can exercize a puppetmaster by simulating an arbitraty number of concurrent clients +# in a lightweight way. +# +# = Prerequisites +# +# This tool requires Event Machine and em-http-request, and an installation of Puppet. +# Event Machine can be installed from gem. +# em-http-request can be installed from gem. +# +# = Usage +# +# puppet-load [-d|--debug] [--concurrency <num>] [--repeat <num>] [-V|--version] [-v|--verbose] +# [--node <host.domain.com>] [--facts <factfile>] [--cert <certfile>] [--key <keyfile>] +# [--factsdir <factsdir>] [--server <server.domain.com>] +# +# = Description +# +# This is a simple script meant for doing performance tests of puppet masters. It does this +# by simulating concurrent connections to a puppet master and asking for catalog compilation. +# +# = Options +# +# Unlike other puppet executables, puppet-load doesn't parse puppet.conf nor use puppet options +# +# debug:: +# Enable full debugging. +# +# concurreny:: +# Number of simulated concurrent clients. +# +# server:: +# Set the puppet master hostname or IP address.. +# +# node:: +# Set the fully-qualified domain name of the client. This option can be given multiple +# times. In this case puppet-load will ask for catalog compilation of all the given nodes +# on a round robin way. +# +# help:: +# Print this help message +# +# facts:: +# This can be used to provide facts for the compilation, directly from a YAML +# file as found in the clientyaml directory. If none are provided, puppet-load +# will look by itself using Puppet facts indirector. +# +# factsdir:: +# Specify a directory where the yaml facts files can be found. If provided puppet-load +# will look up facts in this directory. If not found it will resort to using Puppet Facts +# indirector. +# +# cert:: +# This option is mandatory. It should be set to the cert PEM file that will be used +# to quthenticate the client connections. +# +# key:: +# This option is mandatory. It should be set to the private key PEM file that will be used +# to quthenticate the client connections. +# +# timeout:: +# The number of seconds after which a simulated client is declared in error if it didn't get +# a catalog. The default is 180s. +# +# repeat:: +# How many times to perform the test. This means puppet-load will ask for +# concurrency * repeat catalogs. +# +# verbose:: +# Turn on verbose reporting. +# +# version:: +# Print the puppet version number and exit. +# +# = Example usage +# +# SINGLE NODE: +# 1) On the master host, generate a new certificate and private key for our test host: +# puppet ca --generate puppet-load.domain.com +# +# 2) Copy the cert and key to the puppet-load host (which can be the same as the master one) +# +# 3) On the master host edit or create the auth.conf so that the catalog ACL match: +# path ~ ^/catalog/([^/]+)$ +# method find +# allow $1 +# allow puppet-load.domain.com +# +# 4) launch the master(s) +# +# 5) Prepare or get a fact file. One way to get one is to look on the master in $vardir/yaml/ for the host +# you want to simulate. +# +# 5) launch puppet-load +# puppet-load -debug --node server.domain.com --server master.domain.com --facts server.domain.com.yaml --concurrency 2 --repeat 20 +# +# MULTIPLE NODES: +# 1) On the master host, generate a new certificate and private key for our test host: +# puppet ca --generate puppet-load.domain.com +# +# 2) Copy the cert and key to the puppet-load host (which can be the same as the master one) +# +# 3) On the master host edit or create the auth.conf so that the catalog ACL match: +# path ~ ^/catalog/([^/]+)$ +# method find +# allow $1 +# allow puppet-load.domain.com +# +# 4) launch the master(s) +# +# 5) Prepare or get a fact file. One way to get one is to look on the master in $vardir/yaml/ for the host +# you want to simulate. +# +# 5) launch puppet-load +# puppet-load -debug --node server1.domain.com --node server2.domain.com --node server3.domain.com \ +# --server master.domain.com --factsdir /var/lib/puppet/yaml/facts --concurrency 2 --repeat 20 +# +# puppet-load will load facts file in the --factsdir directory based on the node name. +# +# = TODO +# * More output stats for error connections (ie report errors, HTTP code...) +# +# + +# Do an initial trap, so that cancels don't get a stack trace. +trap(:INT) do + $stderr.puts "Cancelling startup" + exit(1) +end + +require 'rubygems' +require 'eventmachine' +require 'em-http' +require 'getoptlong' +require 'puppet' + +$cmdargs = [ + [ "--concurrency", "-c", GetoptLong::REQUIRED_ARGUMENT ], + [ "--node", "-n", GetoptLong::REQUIRED_ARGUMENT ], + [ "--facts", GetoptLong::REQUIRED_ARGUMENT ], + [ "--factsdir", GetoptLong::REQUIRED_ARGUMENT ], + [ "--repeat", "-r", GetoptLong::REQUIRED_ARGUMENT ], + [ "--cert", "-C", GetoptLong::REQUIRED_ARGUMENT ], + [ "--key", "-k", GetoptLong::REQUIRED_ARGUMENT ], + [ "--timeout", "-t", GetoptLong::REQUIRED_ARGUMENT ], + [ "--server", "-s", GetoptLong::REQUIRED_ARGUMENT ], + [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], + [ "--help", "-h", GetoptLong::NO_ARGUMENT ], + [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], + [ "--version", "-V", GetoptLong::NO_ARGUMENT ], +] + +Puppet::Util::Log.newdestination(:console) + +times = {} + +def read_facts(file) + Puppet.debug("reading facts from: #{file}") + fact = YAML.load(File.read(file)) +end + + +result = GetoptLong.new(*$cmdargs) + +$args = {} +$options = {:repeat => 1, :concurrency => 1, :pause => false, :cert => nil, :key => nil, :timeout => 180, :masterport => 8140, :node => [], :factsdir => nil} + +begin + result.each { |opt,arg| + case opt + when "--concurrency" + begin + $options[:concurrency] = Integer(arg) + rescue => detail + $stderr.puts "The argument to 'fork' must be an integer" + exit(14) + end + when "--node" + $options[:node] << arg + when "--factsdir" + $options[:factsdir] = arg + when "--server" + $options[:server] = arg + when "--masterport" + $options[:masterport] = arg + when "--facts" + $options[:facts] = arg + when "--repeat" + $options[:repeat] = Integer(arg) + when "--help" + if Puppet.features.usage? + RDoc::usage && exit + else + puts "No help available unless you have RDoc::usage installed" + exit + end + when "--version" + puts "%s" % Puppet.version + exit + when "--verbose" + Puppet::Util::Log.level = :info + Puppet::Util::Log.newdestination(:console) + when "--debug" + Puppet::Util::Log.level = :debug + Puppet::Util::Log.newdestination(:console) + when "--cert" + $options[:cert] = arg + when "--key" + $options[:key] = arg + end + } +rescue GetoptLong::InvalidOption => detail + $stderr.puts detail + $stderr.puts "Try '#{$0} --help'" + exit(1) +end + +unless $options[:cert] and $options[:key] + raise "--cert and --key are mandatory to authenticate the client" +end + +parameters = [] + +unless $options[:node].size > 0 + raise "--node is a mandatory argument. It tells to the master what node to compile" +end + +$options[:node].each do |node| + factfile = $options[:factsdir] ? File.join($options[:factsdir], node + ".yaml") : $options[:facts] + unless fact = read_facts(factfile) or fact = Puppet::Node::Facts.find(node) + raise "Could not find facts for %s" % node + end + fact.values["fqdn"] = node + fact.values["hostname"] = node.sub(/\..+/, '') + fact.values["domain"] = node.sub(/^[^.]+\./, '') + + parameters << {:facts_format => "b64_zlib_yaml", :facts => CGI.escape(fact.render(:b64_zlib_yaml))} +end + + +class RequestPool + include EventMachine::Deferrable + + attr_reader :requests, :responses, :times, :sizes + attr_reader :repeat, :concurrency, :max_request + + def initialize(concurrency, repeat, parameters) + @parameters = parameters + @current_request = 0 + @max_request = repeat * concurrency + @repeat = repeat + @concurrency = concurrency + @requests = [] + @responses = {:succeeded => [], :failed => []} + @times = {} + @sizes = {} + + # initial spawn + (1..concurrency).each do |i| + spawn + end + + end + + def spawn_request(index) + @times[index] = Time.now + @sizes[index] = 0 + nodeidx = index % $options[:node].size + node = $options[:node][nodeidx] + EventMachine::HttpRequest.new("https://#{$options[:server]}:#{$options[:masterport]}/production/catalog/#{node}").get( + :port => $options[:masterport], + :query => @parameters[nodeidx], + :timeout => $options[:timeout], + :head => { "Accept" => "pson, yaml, b64_zlib_yaml, marshal, dot, raw", "Accept-Encoding" => "gzip, deflate" }, + :ssl => { :private_key_file => $options[:key], + :cert_chain_file => $options[:cert], + :verify_peer => false } ) do + @times[index] = Time.now + @sizes[index] = 0 + Puppet.debug("starting client #{index} for #{node}") + end + end + + def add(index, conn) + @requests.push(conn) + + conn.stream { |data| + @sizes[index] += data.length + } + + conn.callback { + @times[index] = Time.now - @times[index] + code = conn.response_header.status + if code >= 200 && code < 300 + Puppet.debug("Client #{index} finished successfully") + @responses[:succeeded].push(conn) + else + Puppet.debug("Client #{index} finished with HTTP code #{code}") + @responses[:failed].push(conn) + end + check_progress + } + + conn.errback { + Puppet.debug("Client #{index} finished with an error: #{conn.error}") + @times[index] = Time.now - @times[index] + @responses[:failed].push(conn) + check_progress + } + end + + def all_responses + @responses[:succeeded] + @responses[:failed] + end + + protected + + def check_progress + spawn unless all_spawned? + succeed if all_finished? + end + + def all_spawned? + @requests.size >= max_request + end + + def all_finished? + @responses[:failed].size + @responses[:succeeded].size >= max_request + end + + def spawn + add(@current_request, spawn_request(@current_request)) + @current_request += 1 + end +end + + +def mean(array) + array.inject(0) { |sum, x| sum += x } / array.size.to_f +end + +def median(array) + array = array.sort + m_pos = array.size / 2 + return array.size % 2 == 1 ? array[m_pos] : mean(array[m_pos-1..m_pos]) +end + +def format_bytes(bytes) + if bytes < 1024 + "%.2f B" % bytes + elsif bytes < 1024 * 1024 + "%.2f KiB" % (bytes/1024.0) + else + "%.2f MiB" % (bytes/(1024.0*1024.0)) + end +end + +EM::run { + + start = Time.now + multi = RequestPool.new($options[:concurrency], $options[:repeat], parameters) + + multi.callback do + duration = Time.now - start + puts "#{multi.max_request} requests finished in #{duration} s" + puts "#{multi.responses[:failed].size} requests failed" + puts "Availability: %3.2f %%" % (100.0*multi.responses[:succeeded].size/(multi.responses[:succeeded].size+multi.responses[:failed].size)) + + minmax = multi.times.values.minmax + all_time = multi.times.values.reduce(:+) + + puts "\nTime (s):" + puts "\tmin: #{minmax[0]} s" + puts "\tmax: #{minmax[1]} s" + puts "\taverage: #{mean(multi.times.values)} s" + puts "\tmedian: #{median(multi.times.values)} s" + + puts "\nConcurrency: %.2f" % (all_time/duration) + puts "Transaction Rate (tps): %.2f t/s" % (multi.max_request / duration) + + transferred = multi.sizes.values.reduce(:+) + + puts "\nReceived bytes: #{format_bytes(transferred)}" + puts "Throughput: %.5f MiB/s" % (transferred/duration/(1024.0*1024.0)) + + # this is the end + EventMachine.stop + end +} + + diff --git a/ext/puppetlast b/ext/puppetlast deleted file mode 100755 index 7434368a3..000000000 --- a/ext/puppetlast +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# Puppetlast, a script to output the last check-in time of nodes. Also outputs the cached configuration state, if expired or not. -# -# AJ "Fujin" Christensen <aj@junglist.gen.nz> -# -require 'puppet' -require 'time' - -Puppet[:config] = "/etc/puppet/puppet.conf" -Puppet.parse_config -Puppet[:name] = "puppetmasterd" -Puppet::Node::Facts.terminus_class = :yaml - -Puppet::Node::Facts.search("*").sort { |a,b| a.name <=> b.name }.each do |node| - puts "#{node.name} checked in #{((Time.now - Time.parse(node.values[:_timestamp].to_s)) / 60).floor} minutes ago. Version #{node.values['puppetversion']}#{node.expired? ? ' Cache expired.' : ''}" -end diff --git a/ext/puppetstoredconfigclean.rb b/ext/puppetstoredconfigclean.rb index 34dd72f5d..16f39efa1 100644 --- a/ext/puppetstoredconfigclean.rb +++ b/ext/puppetstoredconfigclean.rb @@ -19,11 +19,11 @@ end opts = GetoptLong.new( - + [ "--config", "-c", GetoptLong::REQUIRED_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ], [ "--usage", "-u", GetoptLong::NO_ARGUMENT ], - + [ "--version", "-v", GetoptLong::NO_ARGUMENT ] ) @@ -54,7 +54,7 @@ printusage(1) unless ARGV.size > 0 require 'puppet/rails' Puppet[:config] = config Puppet.parse_config -pm_conf = Puppet.settings.instance_variable_get(:@values)[:puppetmasterd] +pm_conf = Puppet.settings.instance_variable_get(:@values)[:master] adapter = pm_conf[:dbadapter] args = {:adapter => adapter, :log_level => pm_conf[:rails_loglevel]} @@ -70,8 +70,6 @@ case adapter args[:port] = pm_conf[:dbport] unless pm_conf[:dbport].to_s.empty? socket = pm_conf[:dbsocket] args[:socket] = socket unless socket.to_s.empty? - connections = pm_conf[:dbconnections].to_i - args[:pool] = connections if connections > 0 else raise ArgumentError, "Invalid db adapter #{adapter}" end diff --git a/ext/rack/files/config.ru b/ext/rack/files/config.ru index 5f0834a7d..f9c492dd7 100644 --- a/ext/rack/files/config.ru +++ b/ext/rack/files/config.ru @@ -4,15 +4,13 @@ # if puppet is not in your RUBYLIB: # $:.unshift('/opt/puppet/lib') -$0 = "puppetmasterd" -require 'puppet' +$0 = "master" # if you want debugging: # ARGV << "--debug" ARGV << "--rack" -require 'puppet/application/puppetmasterd' +require 'puppet/application/master' # we're usually running inside a Rack::Builder.new {} block, # therefore we need to call run *here*. -run Puppet::Application[:puppetmasterd].run - +run Puppet::Application[:master].run diff --git a/ext/vim/syntax/puppet.vim b/ext/vim/syntax/puppet.vim index 80cd91c6c..96052104d 100644 --- a/ext/vim/syntax/puppet.vim +++ b/ext/vim/syntax/puppet.vim @@ -19,7 +19,7 @@ endif " match class/definition/node declarations syn region puppetDefine start="^\s*\(class\|define\|node\)\s" end="{" contains=puppetDefType,puppetDefName,puppetDefArguments,puppetNodeRe syn keyword puppetDefType class define node inherits contained -syn region puppetDefArguments start="(" end=")" contained contains=puppetArgument +syn region puppetDefArguments start="(" end=")" contained contains=puppetArgument,puppetString syn match puppetArgument "\w\+" contained syn match puppetArgument "\$\w\+" contained syn match puppetArgument "'[^']+'" contained @@ -33,6 +33,7 @@ syn match puppetNodeRe "/.*/" contained "FIXME: "Foo-bar" doesn't get highlighted as expected, although "foo-bar" does. syn match puppetInstance "[A-Za-z0-9_-]\+\(::[A-Za-z0-9_-]\+\)*\s*{" contains=puppetTypeName,puppetTypeDefault syn match puppetInstance "[A-Z][a-z_-]\+\(::[A-Z][a-z_-]\+\)*\s*[[{]" contains=puppetTypeName,puppetTypeDefault +syn match puppetInstance "[A-Z][a-z_-]\+\(::[A-Z][a-z_-]\+\)*\s*<\?<|" contains=puppetTypeName,puppetTypeDefault syn match puppetTypeName "[a-z]\w*" contained syn match puppetTypeDefault "[A-Z]\w*" contained @@ -56,19 +57,19 @@ syn region puppetFunction start="^\s*\(alert\|crit\|debug\|emerg\|err\|fai " rvalues syn region puppetFunction start="^\s*\(defined\|file\|fqdn_rand\|generate\|inline_template\|regsubst\|sha1\|shellquote\|split\|sprintf\|tagged\|template\|versioncmp\)\s*(" end=")" contained contains=puppetString -syn match puppetVariable "$\w\+" -syn match puppetVariable "${\w\+}" +syn match puppetVariable "$[a-zA-Z0-9_:]\+" +syn match puppetVariable "${[a-zA-Z0-9_:]\+}" " match anything between simple/double quotes. " don't match variables if preceded by a backslash. syn region puppetString start=+'+ skip=+\\\\\|\\'+ end=+'+ syn region puppetString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=puppetVariable,puppetNotVariable -syn match puppetString "/.*/" +syn match puppetString "/[^/]*/" syn match puppetNotVariable "\\$\w\+" contained syn match puppetNotVariable "\\${\w\+}" contained syn keyword puppetKeyword import inherits include -syn keyword puppetControl case default if else +syn keyword puppetControl case default if else elsif syn keyword puppetSpecial true false undef " comments last overriding everything else diff --git a/install.rb b/install.rb index b06ec09fd..f7541c854 100755 --- a/install.rb +++ b/install.rb @@ -55,13 +55,13 @@ end begin if $haverdoc - rst2man = %x{which rst2man.py} + ronn = %x{which ronn} $haveman = true else $haveman = false end rescue - puts "Missing rst2man; skipping man page creation" + puts "Missing ronn; skipping man page creation" $haveman = false end @@ -88,6 +88,7 @@ libs = glob(%w{lib/**/*.rb lib/**/*.py lib/puppet/util/command_line/*}) tests = glob(%w{test/**/*.rb}) def do_bins(bins, target, strip = 's?bin/') + Dir.mkdir(target) unless File.directory? target bins.each do |bf| obf = bf.gsub(/#{strip}/, '') install_binfile(bf, obf, target) @@ -154,10 +155,12 @@ end # Prepare the file installation. # def prepare_installation + $operatingsystem = Facter["operatingsystem"].value + # Only try to do docs if we're sure they have rdoc if $haverdoc InstallOptions.rdoc = true - InstallOptions.ri = RUBY_PLATFORM != "i386-mswin32" + InstallOptions.ri = $operatingsystem != "windows" else InstallOptions.rdoc = false InstallOptions.ri = false @@ -166,7 +169,7 @@ def prepare_installation if $haveman InstallOptions.man = true - if RUBY_PLATFORM == "i386-mswin32" + if $operatingsystem == "windows" InstallOptions.man = false end else @@ -175,15 +178,6 @@ def prepare_installation InstallOptions.tests = true - if $haveman - InstallOptions.man = true - if RUBY_PLATFORM == "i386-mswin32" - InstallOptions.man = false - end - else - InstallOptions.man = false - end - ARGV.options do |opts| opts.banner = "Usage: #{File.basename($0)} [options]" opts.separator "" @@ -347,21 +341,22 @@ end def build_man(bins, sbins) return unless $haveman begin - # Locate rst2man - rst2man = %x{which rst2man.py} - rst2man.chomp! + # Locate ronn + ronn = %x{which ronn} + ronn.chomp! # Create puppet.conf.5 man page - %x{bin/puppetdoc --reference configuration > ./puppet.conf.rst} - %x{#{rst2man} ./puppet.conf.rst ./man/man5/puppet.conf.5} - File.unlink("./puppet.conf.rst") + %x{bin/puppetdoc --reference configuration > ./man/man5/puppetconf.5.ronn} + %x{#{ronn} -r ./man/man5/puppetconf.5.ronn} + File.move("./man/man5/puppetconf.5", "./man/man5/puppet.conf.5") + File.unlink("./man/man5/puppetconf.5.ronn") # Create binary man pages binary = bins + sbins binary.each do |bin| b = bin.gsub( /(bin|sbin)\//, "") - %x{#{bin} --help > ./#{b}.rst} - %x{#{rst2man} ./#{b}.rst ./man/man8/#{b}.8} - File.unlink("./#{b}.rst") + %x{#{bin} --help > ./man/man8/#{b}.8.ronn} + %x{#{ronn} -r ./man/man8/#{b}.8.ronn} + File.unlink("./man/man8/#{b}.8.ronn") end rescue SystemCallError @@ -417,7 +412,7 @@ def install_binfile(from, op_file, target) end end - if Config::CONFIG["target_os"] =~ /win/io and Config::CONFIG["target_os"] !~ /darwin/io + if $operatingsystem == "windows" installed_wrapper = false if File.exists?("#{from}.bat") @@ -467,4 +462,4 @@ prepare_installation do_bins(sbins, InstallOptions.sbin_dir) do_bins(bins, InstallOptions.bin_dir) do_libs(libs) -do_man(man) +do_man(man) unless $operatingsystem == "windows" diff --git a/lib/puppet.rb b/lib/puppet.rb index 902f5bf5c..78fb5138b 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -24,7 +24,7 @@ require 'puppet/util/run_mode' # it's also a place to find top-level commands like 'debug' module Puppet - PUPPETVERSION = '2.6.0' + PUPPETVERSION = '2.6.3' def Puppet.version PUPPETVERSION diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb index 52acc64aa..47dd44a0e 100644 --- a/lib/puppet/agent.rb +++ b/lib/puppet/agent.rb @@ -37,7 +37,9 @@ class Puppet::Agent with_client do |client| begin sync.synchronize { lock { result = client.run(*args) } } - rescue => detail + rescue SystemExit,NoMemoryError + raise + rescue Exception => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not run #{client_class}: #{detail}" end diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb index 05b7d466f..f0159a65d 100644 --- a/lib/puppet/application.rb +++ b/lib/puppet/application.rb @@ -254,20 +254,6 @@ class Application def preinit end - def option_parser - return @option_parser if defined?(@option_parser) - - @option_parser = OptionParser.new(self.class.banner) - - self.class.option_parser_commands.each do |options, fname| - @option_parser.on(*options) do |value| - self.send(fname, value) - end - end - @option_parser.default_argv = self.command_line.args - @option_parser - end - def initialize(command_line = nil) require 'puppet/util/command_line' @command_line = command_line || Puppet::Util::CommandLine.new @@ -286,7 +272,7 @@ class Application Puppet.settings.set_value(:name, Puppet.application_name.to_s, :mutable_defaults) Puppet.settings.set_value(:logdir, Puppet.run_mode.logopts, :mutable_defaults) Puppet.settings.set_value(:rundir, Puppet.run_mode.run_dir, :mutable_defaults) - Puppet.settings.set_value(:mode, Puppet.run_mode.name.to_s, :mutable_defaults) + Puppet.settings.set_value(:run_mode, Puppet.run_mode.name.to_s, :mutable_defaults) end require 'puppet' @@ -324,20 +310,29 @@ class Application end def parse_options - # get all puppet options - optparse_opt = [] - optparse_opt = Puppet.settings.optparse_addargs(optparse_opt) + # Create an option parser + option_parser = OptionParser.new(self.class.banner) - # convert them to OptionParser format - optparse_opt.each do |option| - self.option_parser.on(*option) do |arg| + # Add all global options to it. + Puppet.settings.optparse_addargs([]).each do |option| + option_parser.on(*option) do |arg| handlearg(option[0], arg) end end - # scan command line argument + # Add options that are local to this application, which were + # created using the "option()" metaprogramming method. If there + # are any conflicts, this application's options will be favored. + self.class.option_parser_commands.each do |options, fname| + option_parser.on(*options) do |value| + # Call the method that "option()" created. + self.send(fname, value) + end + end + + # scan command line. begin - self.option_parser.parse! + option_parser.parse!(self.command_line.args) rescue OptionParser::ParseError => detail $stderr.puts detail $stderr.puts "Try 'puppet #{command_line.subcommand_name} --help'" diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb index f0e7f4d8f..c5ad72068 100644 --- a/lib/puppet/application/agent.rb +++ b/lib/puppet/application/agent.rb @@ -219,12 +219,18 @@ class Puppet::Application::Agent < Puppet::Application Puppet.settings.use :main, :agent, :ssl + # Always ignoreimport for agent. It really shouldn't even try to import, + # but this is just a temporary band-aid. + Puppet[:ignoreimport] = true + # We need to specify a ca location for all of the SSL-related i # indirected classes to work; in fingerprint mode we just need # access to the local files and we don't need a ca. Puppet::SSL::Host.ca_location = options[:fingerprint] ? :none : :remote Puppet::Transaction::Report.terminus_class = :rest + # we want the last report to be persisted locally + Puppet::Transaction::Report.cache_class = :yaml # Override the default; puppetd needs this, usually. # You can still override this on the command-line with, e.g., :compiler. diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb index bb4186dbd..8ec3fab6b 100644 --- a/lib/puppet/application/apply.rb +++ b/lib/puppet/application/apply.rb @@ -78,7 +78,10 @@ class Puppet::Application::Apply < Puppet::Application if options[:code] or command_line.args.length == 0 Puppet[:code] = options[:code] || STDIN.read else - Puppet[:manifest] = command_line.args.shift + manifest = command_line.args.shift + raise "Could not find file #{manifest}" unless File.exist?(manifest) + Puppet.warning("Only one file can be applied per run. Skipping #{command_line.args.join(', ')}") if command_line.args.size > 0 + Puppet[:manifest] = manifest end # Collect our facts. @@ -120,20 +123,9 @@ class Puppet::Application::Apply < Puppet::Application require 'puppet/configurer' configurer = Puppet::Configurer.new - configurer.execute_prerun_command - - # And apply it - transaction = catalog.apply - - configurer.execute_postrun_command + report = configurer.run(:skip_plugin_download => true, :catalog => catalog) - status = 0 - if not Puppet[:noop] and options[:detailed_exitcodes] - transaction.generate_report - exit(transaction.report.exit_status) - else - exit(0) - end + exit( Puppet[:noop] ? 0 : options[:detailed_exitcodes] ? report.exit_status : 0 ) rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts detail.message @@ -156,6 +148,9 @@ class Puppet::Application::Apply < Puppet::Application exit(1) end + # we want the last report to be persisted locally + Puppet::Transaction::Report.cache_class = :yaml + if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] diff --git a/lib/puppet/application/describe.rb b/lib/puppet/application/describe.rb index 5abe3ea14..e76b347f6 100644 --- a/lib/puppet/application/describe.rb +++ b/lib/puppet/application/describe.rb @@ -130,7 +130,7 @@ class TypeDoc a[0].to_s <=> b[0].to_s }.each { |name, doc| print "\n- **#{name}**" - if type.namevar == name and name != :name + if type.key_attributes.include?(name) and name != :name puts " (*namevar*)" else puts "" diff --git a/lib/puppet/application/doc.rb b/lib/puppet/application/doc.rb index 66aa6c8a1..1f6c63286 100644 --- a/lib/puppet/application/doc.rb +++ b/lib/puppet/application/doc.rb @@ -56,7 +56,7 @@ class Puppet::Application::Doc < Puppet::Application end def run_command - return[:rdoc, :trac, :markdown].include?(options[:mode]) ? send(options[:mode]) : other + return[:rdoc].include?(options[:mode]) ? send(options[:mode]) : other end def rdoc @@ -72,7 +72,7 @@ class Puppet::Application::Doc < Puppet::Application Puppet.settings.setdefaults( "puppetdoc", - + "document_all" => [false, "Document all resources"] ) Puppet.settings[:document_all] = options[:all] || false @@ -92,40 +92,6 @@ class Puppet::Application::Doc < Puppet::Application exit exit_code end - def trac - require 'puppet/util/reference' - options[:references].each do |name| - section = Puppet::Util::Reference.reference(name) or raise "Could not find section #{name}" - section.trac unless options[:mode] == :pdf - end - end - - def markdown - text = "" - with_contents = false - exit_code = 0 - require 'puppet/util/reference' - options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name| - raise "Could not find reference #{name}" unless section = Puppet::Util::Reference.reference(name) - - begin - # Add the per-section text, but with no ToC - text += section.send(options[:format], with_contents) - text += Puppet::Util::Reference.footer - text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 } - Puppet::Util::Reference.markdown(name, text) - text = "" - rescue => detail - puts detail.backtrace - $stderr.puts "Could not generate reference #{name}: #{detail}" - exit_code = 1 - next - end - end - - exit exit_code - end - def other text = "" with_contents = options[:references].length <= 1 diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb index 777a50eaa..fde474907 100644 --- a/lib/puppet/application/master.rb +++ b/lib/puppet/application/master.rb @@ -138,9 +138,6 @@ class Puppet::Application::Master < Puppet::Application Puppet.settings.use :main, :master, :ssl - # A temporary solution, to at least make the master work for now. - Puppet::Node::Facts.terminus_class = :yaml - # Cache our nodes in yaml. Currently not configurable. Puppet::Node.cache_class = :yaml diff --git a/lib/puppet/application/queue.rb b/lib/puppet/application/queue.rb index 6df825dd1..239f6b2ad 100644 --- a/lib/puppet/application/queue.rb +++ b/lib/puppet/application/queue.rb @@ -38,6 +38,7 @@ class Puppet::Application::Queue < Puppet::Application option("--verbose","-v") def main + require 'puppet/indirector/catalog/queue' # provides Puppet::Indirector::Queue.subscribe Puppet.notice "Starting puppetqd #{Puppet.version}" Puppet::Resource::Catalog::Queue.subscribe do |catalog| # Once you have a Puppet::Resource::Catalog instance, calling save on it should suffice diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index 327955b03..1c0639029 100644 --- a/lib/puppet/configurer.rb +++ b/lib/puppet/configurer.rb @@ -77,12 +77,12 @@ class Puppet::Configurer end # Prepare for catalog retrieval. Downloads everything necessary, etc. - def prepare + def prepare(options) dostorage - download_plugins + download_plugins unless options[:skip_plugin_download] - download_fact_plugins + download_fact_plugins unless options[:skip_plugin_download] execute_prerun_command end @@ -126,7 +126,7 @@ class Puppet::Configurer # which accepts :tags and :ignoreschedules. def run(options = {}) begin - prepare + prepare(options) rescue SystemExit,NoMemoryError raise rescue Exception => detail @@ -158,25 +158,40 @@ class Puppet::Configurer return end ensure + # Make sure we forget the retained module_directories of any autoload + # we might have used. + Thread.current[:env_module_directories] = nil + # Now close all of our existing http connections, since there's no # reason to leave them lying open. Puppet::Network::HttpPool.clear_http_instances execute_postrun_command Puppet::Util::Log.close(report) - send_report(report, transaction) end def send_report(report, trans = nil) trans.generate_report if trans puts report.summary if Puppet[:summarize] - report.save if Puppet[:report] + save_last_run_summary(report) + if Puppet[:report] + report.save + end rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not send report: #{detail}" end + def save_last_run_summary(report) + Puppet::Util::FileLocking.writelock(Puppet[:lastrunfile], 0660) do |file| + file.print YAML.dump(report.raw_summary) + end + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Could not save last run local report: #{detail}" + end + private def self.timeout diff --git a/lib/puppet/daemon.rb b/lib/puppet/daemon.rb index aa4a12bfa..c76d63a54 100755 --- a/lib/puppet/daemon.rb +++ b/lib/puppet/daemon.rb @@ -43,7 +43,7 @@ class Puppet::Daemon # Create a pidfile for our daemon, so we can be stopped and others # don't try to start. def create_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock end end @@ -73,7 +73,7 @@ class Puppet::Daemon # Remove the pid file for our daemon. def remove_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do locker = Puppet::Util::Pidlock.new(pidfile) locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked? end @@ -121,8 +121,8 @@ class Puppet::Daemon create_pidfile raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server - agent.start if agent server.start if server + agent.start if agent EventLoop.current.run end diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 84e2d93fc..8bf1cd84d 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -2,12 +2,12 @@ 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 master`` 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 ``~``."], + is running as root or the user that `puppet master` 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 `~`."], :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``."], - :mode => [Puppet.run_mode.name.to_s, "The effective 'run mode' of the application: master, agent, or user."] + 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) @@ -44,8 +44,8 @@ module Puppet specify 'all'. This feature is only available in Puppet versions higher than 0.18.4."], :color => ["ansi", "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 + 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 @@ -92,18 +92,18 @@ module Puppet :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``." + 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 + (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."], + This feature currently requires the `diff/lcs` Ruby library."], :daemonize => { :default => true, :desc => "Send the process into the background. This is the default.", :short => "D" @@ -115,7 +115,17 @@ module Puppet :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 => ["facter", "Where to get node facts."], + :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.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, @@ -135,7 +145,7 @@ module Puppet :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.", + 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 @@ -266,10 +276,9 @@ module Puppet to all clients. If enabled, CA chaining will almost definitely not work."] ) - setdefaults( :ca, - :ca_name => ["$certname", "The name to use the Certificate Authority certificate."], + :ca_name => ["Puppet CA: $certname", "The name to use the Certificate Authority certificate."], :cadir => { :default => "$ssldir/ca", :owner => "service", :group => "service", @@ -385,7 +394,7 @@ module Puppet :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 + by `puppet`, and should only be set if you're writing your own Puppet executable"], :masterlog => { :default => "$logdir/puppetmaster.log", :owner => "service", @@ -419,7 +428,7 @@ module Puppet :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``." + authorization system for `puppet master`." ], :ca => [true, "Wether the master should function as a certificate authority."], :modulepath => {:default => "$confdir/modules:/usr/share/puppet/modules", @@ -427,7 +436,7 @@ module Puppet directories.", :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``). + 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 @@ -441,10 +450,25 @@ module Puppet :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 + 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", + "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", :owner => "service", :group => "service", @@ -453,10 +477,7 @@ module Puppet this directory." }, :rrdinterval => ["$runinterval", "How often RRD should expect data. - This should match how often the hosts report back to the server."], - :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."] + This should match how often the hosts report back to the server."] ) setdefaults(:agent, @@ -479,7 +500,7 @@ module Puppet :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`` + the separate `puppet` executable using the `--loadclasses` option."}, :puppetdlog => { :default => "$logdir/puppetd.log", :owner => "root", @@ -496,8 +517,8 @@ module Puppet "How often puppet agent applies the client configuration; in seconds."], :listen => [false, "Whether puppet agent should listen for connections. If this is true, then by default only the - ``runner`` server is started, which allows remote authorized - and authenticated nodes to connect and trigger ``puppet agent`` + `runner` server is started, which allows remote authorized + and authenticated nodes to connect and trigger `puppet agent` runs."], :ca_server => ["$server", "The server to use for certificate authority requests. It's a separate server because it cannot @@ -567,14 +588,28 @@ module Puppet end }, :report_server => ["$server", - "The server to which to send transaction reports." + "The server to send transaction reports to." ], :report_port => ["$masterport", "The port to communicate with the report_server." ], - :report => [false, + :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)."], @@ -595,7 +630,7 @@ module Puppet "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 + "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."], @@ -607,7 +642,7 @@ module Puppet setdefaults( :main, - :factpath => {:default => "$vardir/lib/facter/${File::PATH_SEPARATOR}$vardir/facts", + :factpath => {:default => "$vardir/lib/facter:$vardir/facts", :desc => "Where Puppet should look for facts. Multiple directories should be colon-separated, like normal PATH variables.", @@ -618,33 +653,23 @@ module Puppet "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 + "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."], - :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", - "The URL used by the http reports processor to send reports"] + :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 => [%x{which sendmail 2>/dev/null}.chomp, "Where to find the sendmail binary with which to send email."], + :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", @@ -665,11 +690,10 @@ module Puppet 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."], - :dbconnections => [ 0, "The number of database connections. Only used when - networked databases are used. Will be ignored if the value is an empty - string or is less than 1."], :railslog => {:default => "$logdir/rails.log", :mode => 0600, :owner => "service", @@ -678,18 +702,16 @@ module Puppet }, :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``."] + 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 @@ -704,21 +726,19 @@ module Puppet ] ) - 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 + `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, @@ -733,9 +753,9 @@ module Puppet 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."], + "The LDAP server. Only used if `ldapnodes` is enabled."], :ldapport => [389, - "The LDAP port. Only used if ``ldapnodes`` is enabled."], + "The LDAP port. Only used if `ldapnodes` is enabled."], :ldapstring => ["(&(objectclass=puppetClient)(cn=%s))", "The search string used to find an LDAP node."], diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb index abdb78f67..97a310436 100644 --- a/lib/puppet/dsl.rb +++ b/lib/puppet/dsl.rb @@ -5,7 +5,3 @@ end require 'puppet/dsl/resource_type_api' require 'puppet/dsl/resource_api' - -class Object - include Puppet::DSL::ResourceTypeAPI -end diff --git a/lib/puppet/dsl/resource_type_api.rb b/lib/puppet/dsl/resource_type_api.rb index 487aab99d..8810d5368 100644 --- a/lib/puppet/dsl/resource_type_api.rb +++ b/lib/puppet/dsl/resource_type_api.rb @@ -1,34 +1,15 @@ require 'puppet/resource/type' -module Puppet::DSL::ResourceTypeAPI - def define(name, *args, &block) - result = mk_resource_type(:definition, name, Hash.new, block) - result.set_arguments(munge_type_arguments(args)) - result - end - - def hostclass(name, options = {}, &block) - mk_resource_type(:hostclass, name, options, block) - end - - def node(name, options = {}, &block) - mk_resource_type(:node, name, options, block) - end - - private - - def mk_resource_type(type, name, options, code) - klass = Puppet::Resource::Type.new(type, name, options) - - klass.ruby_code = code if code - - Puppet::Node::Environment.new.known_resource_types.add klass - - klass +# Type of the objects inside of which pure ruby manifest files are +# executed. Provides methods for creating defines, hostclasses, and +# nodes. +class Puppet::DSL::ResourceTypeAPI + def initialize + @__created_ast_objects__ = [] end - def munge_type_arguments(args) - args.inject([]) do |result, item| + def define(name, *args, &block) + args = args.inject([]) do |result, item| if item.is_a?(Hash) item.each { |p, v| result << [p, v] } else @@ -36,5 +17,18 @@ module Puppet::DSL::ResourceTypeAPI end result end + @__created_ast_objects__.push Puppet::Parser::AST::Definition.new(name, {:arguments => args}, &block) + nil + end + + def hostclass(name, options = {}, &block) + @__created_ast_objects__.push Puppet::Parser::AST::Hostclass.new(name, options, &block) + nil + end + + def node(name, options = {}, &block) + name = [name] unless name.is_a?(Array) + @__created_ast_objects__.push Puppet::Parser::AST::Node.new(name, options, &block) + nil end end diff --git a/lib/puppet/external/event-loop/event-loop.rb b/lib/puppet/external/event-loop/event-loop.rb index dc51a55ae..3b40f6e71 100644 --- a/lib/puppet/external/event-loop/event-loop.rb +++ b/lib/puppet/external/event-loop/event-loop.rb @@ -75,8 +75,10 @@ class EventLoop @notify_src, @notify_snk = IO.pipe # prevent file descriptor leaks - @notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) - @notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + if @notify_src.respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_SETFD) and defined?(Fcntl::FD_CLOEXEC) + @notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + @notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + end @notify_src.will_block = false @notify_snk.will_block = false @@ -234,19 +236,21 @@ class IO end def will_block? - require "fcntl" - fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0 + if respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_GETFL) and defined?(Fcntl::O_NONBLOCK) + fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0 + end end def will_block= (wants_blocking) - require "fcntl" - flags = fcntl(Fcntl::F_GETFL, 0) - if wants_blocking - flags &= ~Fcntl::O_NONBLOCK - else - flags |= Fcntl::O_NONBLOCK + if respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_GETFL) and defined?(Fcntl::O_NONBLOCK) + flags = fcntl(Fcntl::F_GETFL, 0) + if wants_blocking + flags &= ~Fcntl::O_NONBLOCK + else + flags |= Fcntl::O_NONBLOCK + end + fcntl(Fcntl::F_SETFL, flags) end - fcntl(Fcntl::F_SETFL, flags) end end diff --git a/lib/puppet/external/pson/pure/generator.rb b/lib/puppet/external/pson/pure/generator.rb index ef8b36d31..89a0c62e0 100644 --- a/lib/puppet/external/pson/pure/generator.rb +++ b/lib/puppet/external/pson/pure/generator.rb @@ -44,41 +44,13 @@ module PSON string << '' # XXX workaround: avoid buffer sharing string.force_encoding(Encoding::ASCII_8BIT) string.gsub!(/["\\\x0-\x1f]/) { MAP[$MATCH] } - string.gsub!(/( - (?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+ | - [\x80-\xc1\xf5-\xff] # invalid - )/nx) { |c| - c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'" - s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0] - s.gsub!(/.{4}/n, '\\\\u\&') - } - string.force_encoding(Encoding::UTF_8) string rescue Iconv::Failure => e raise GeneratorError, "Caught #{e.class}: #{e}" end else def utf8_to_pson(string) # :nodoc: - string = string.gsub(/["\\\x0-\x1f]/) { MAP[$MATCH] } - string.gsub!(/( - (?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+ | - [\x80-\xc1\xf5-\xff] # invalid - )/nx) { |c| - c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'" - s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0] - s.gsub!(/.{4}/n, '\\\\u\&') - } - string - rescue Iconv::Failure => e - raise GeneratorError, "Caught #{e.class}: #{e}" + string.gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] } end end module_function :utf8_to_pson diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb index c153fba98..c983f5c12 100644 --- a/lib/puppet/feature/base.rb +++ b/lib/puppet/feature/base.rb @@ -27,7 +27,8 @@ Puppet.features.add :diff, :libs => %w{diff/lcs diff/lcs/hunk} Puppet.features.add(:augeas, :libs => ["augeas"]) # We have RRD available -Puppet.features.add(:rrd, :libs => ["RRDtool"]) +Puppet.features.add(:rrd_legacy, :libs => ["RRDtool"]) +Puppet.features.add(:rrd, :libs => ["RRD"]) # We have OpenSSL Puppet.features.add(:openssl, :libs => ["openssl"]) diff --git a/lib/puppet/feature/rails.rb b/lib/puppet/feature/rails.rb index e0e14ebeb..74ed09aa6 100644 --- a/lib/puppet/feature/rails.rb +++ b/lib/puppet/feature/rails.rb @@ -24,9 +24,7 @@ Puppet.features.add(:rails) do end end - if ! (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR)) - false - elsif ! (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR >= 1) + unless (Puppet::Util.activerecord_version >= 2.1) Puppet.info "ActiveRecord 2.1 or later required for StoreConfigs" false else diff --git a/lib/puppet/file_serving/indirection_hooks.rb b/lib/puppet/file_serving/indirection_hooks.rb index 7e0c17916..a85e90ef1 100644 --- a/lib/puppet/file_serving/indirection_hooks.rb +++ b/lib/puppet/file_serving/indirection_hooks.rb @@ -19,8 +19,8 @@ module Puppet::FileServing::IndirectionHooks return PROTOCOL_MAP["file"] if request.key =~ /^#{::File::SEPARATOR}/ return PROTOCOL_MAP["file"] if request.protocol == "file" - # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'puppet' - if request.protocol == "puppet" and (request.server or Puppet.settings[:name] != "puppet") + # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'apply' or 'puppet' + if request.protocol == "puppet" and (request.server or !["puppet","apply"].include?(Puppet.settings[:name])) return PROTOCOL_MAP["puppet"] end diff --git a/lib/puppet/indirector/catalog/compiler.rb b/lib/puppet/indirector/catalog/compiler.rb index c50022fff..78be4caf7 100644 --- a/lib/puppet/indirector/catalog/compiler.rb +++ b/lib/puppet/indirector/catalog/compiler.rb @@ -22,6 +22,7 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code else facts = Puppet::Node::Facts.convert_from(format, text_facts) end + facts.add_timestamp facts.save end @@ -107,10 +108,14 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code return node end - # If the request is authenticated, then the 'node' info will - # be available; if not, then we use the passed-in key. We rely - # on our authorization system to determine whether this is allowed. - name = request.node || request.key + # We rely on our authorization system to determine whether the connected + # node is allowed to compile the catalog's node referenced by key. + # By default the REST authorization system makes sure only the connected node + # can compile his catalog. + # This allows for instance monitoring systems or puppet-load to check several + # node's catalog with only one certificate and a modification to auth.conf + # If no key is provided we can only compile the currently connected node. + name = request.key || request.node if node = find_node(name) return node end diff --git a/lib/puppet/indirector/facts/memory.rb b/lib/puppet/indirector/facts/memory.rb index c4ca19da5..93682f456 100644 --- a/lib/puppet/indirector/facts/memory.rb +++ b/lib/puppet/indirector/facts/memory.rb @@ -3,7 +3,7 @@ require 'puppet/indirector/memory' class Puppet::Node::Facts::Memory < Puppet::Indirector::Memory desc "Keep track of facts in memory but nowhere else. This is used for - one-time compiles, such as what the stand-alone ``puppet`` does. + one-time compiles, such as what the stand-alone `puppet` does. To use this terminus, you must load it with the data you want it to contain." end diff --git a/lib/puppet/indirector/facts/rest.rb b/lib/puppet/indirector/facts/rest.rb index 07491fc77..e2afa14b2 100644 --- a/lib/puppet/indirector/facts/rest.rb +++ b/lib/puppet/indirector/facts/rest.rb @@ -3,4 +3,6 @@ require 'puppet/indirector/rest' class Puppet::Node::Facts::Rest < Puppet::Indirector::REST desc "Find and save facts about nodes over HTTP via REST." + use_server_setting(:inventory_server) + use_port_setting(:inventory_port) end diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb index 309eed7b6..9095e48f8 100644 --- a/lib/puppet/indirector/indirection.rb +++ b/lib/puppet/indirector/indirection.rb @@ -238,6 +238,7 @@ class Puppet::Indirector::Indirection if result = terminus.search(request) raise Puppet::DevError, "Search results from terminus #{terminus.name} are not an array" unless result.is_a?(Array) result.each do |instance| + next unless instance.respond_to? :expiration instance.expiration ||= self.expiration end return result diff --git a/lib/puppet/indirector/inventory/yaml.rb b/lib/puppet/indirector/inventory/yaml.rb new file mode 100644 index 000000000..fe3489a95 --- /dev/null +++ b/lib/puppet/indirector/inventory/yaml.rb @@ -0,0 +1,81 @@ +require 'puppet/node/inventory' +require 'puppet/indirector/yaml' + +class Puppet::Node::Inventory::Yaml < Puppet::Indirector::Yaml + desc "Return node names matching the fact query" + + # Return the path to a given node's file. + def yaml_dir_path + base = Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir] + File.join(base, 'facts', '*.yaml') + end + + def node_matches?(facts, options) + options.each do |key, value| + type, name, operator = key.to_s.split(".") + operator ||= 'eq' + + return false unless node_matches_option?(type, name, operator, value, facts) + end + return true + end + + def search(request) + node_names = [] + Dir.glob(yaml_dir_path).each do |file| + facts = YAML.load_file(file) + node_names << facts.name if node_matches?(facts, request.options) + end + node_names + end + + private + + def node_matches_option?(type, name, operator, value, facts) + case type + when "meta" + case name + when "timestamp" + compare_timestamp(operator, facts.timestamp, Time.parse(value)) + end + when "facts" + compare_facts(operator, facts.values[name], value) + end + end + + def compare_facts(operator, value1, value2) + return false unless value1 + + case operator + when "eq" + value1.to_s == value2.to_s + when "le" + value1.to_f <= value2.to_f + when "ge" + value1.to_f >= value2.to_f + when "lt" + value1.to_f < value2.to_f + when "gt" + value1.to_f > value2.to_f + when "ne" + value1.to_s != value2.to_s + end + end + + def compare_timestamp(operator, value1, value2) + case operator + when "eq" + value1 == value2 + when "le" + value1 <= value2 + when "ge" + value1 >= value2 + when "lt" + value1 < value2 + when "gt" + value1 > value2 + when "ne" + value1 != value2 + end + end +end diff --git a/lib/puppet/indirector/node/exec.rb b/lib/puppet/indirector/node/exec.rb index c3e690943..6e065c6f3 100644 --- a/lib/puppet/indirector/node/exec.rb +++ b/lib/puppet/indirector/node/exec.rb @@ -3,7 +3,7 @@ require 'puppet/indirector/exec' class Puppet::Node::Exec < Puppet::Indirector::Exec desc "Call an external program to get node information. See - the `ExternalNodes`:trac: page for more information." + the [External Nodes](http://docs.puppetlabs.com/guides/external_nodes.html) page for more information." include Puppet::Util def command diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb index b9fe35575..5fd738511 100644 --- a/lib/puppet/indirector/node/ldap.rb +++ b/lib/puppet/indirector/node/ldap.rb @@ -3,9 +3,9 @@ require 'puppet/indirector/ldap' class Puppet::Node::Ldap < Puppet::Indirector::Ldap desc "Search in LDAP for node configuration information. See - the `LdapNodes`:trac: page for more information. This will first + the [LDAP Nodes](http://projects.puppetlabs.com/projects/puppet/wiki/Ldap_Nodes) page for more information. This will first search for whatever the certificate name is, then (if that name - contains a '.') for the short name, then 'default'." + contains a `.`) for the short name, then `default`." # The attributes that Puppet class information is stored in. def class_attributes @@ -19,30 +19,10 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap # LAK:NOTE Unfortunately, the ldap support is too stupid to throw anything # but LDAP::ResultError, even on bad connections, so we are rough handed # with our error handling. - def name2hash(name,name_env,node_type) + def name2hash(name) info = nil - ldapsearch(search_filter(name)) { - |entry| info = entry2hash(entry) - if info[:environment] - if name_env == info[:environment] - return info - else - info = nil - end - else - info_env = "production" - if name_env == info[:environment] - return info - else - info = nil - end - end - } - if node_type == 'parent' - raise Puppet::Error.new("Could not find node '#{name}' with environment '#{name_env}'") - end - - info = name2hash('default',name_env,'parent') + ldapsearch(search_filter(name)) { |entry| info = entry2hash(entry) } + info end # Look for our node in ldap. @@ -53,18 +33,9 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap node = nil names.each do |name| - facts = Puppet::Node::Facts.find(name) - if facts.values["environment"] - name_env = facts.values["environment"] - else - name_env = "production" - end - info = name2hash(name,name_env,'child') - next if info == nil + next unless info = name2hash(name) - if info - break if node = info2node(request.key, info) - end + break if node = info2node(request.key, info) end node @@ -200,29 +171,14 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap # Find information for our parent and merge it into the current info. def find_and_merge_parent(parent, information) - - if information[:environment] - name_env = information[:environment] - else - name_env = 'production' - end - - parent_info = name2hash(parent,name_env,'parent') - if parent_info + parent_info = name2hash(parent) || raise(Puppet::Error.new("Could not find parent node '#{parent}'")) information[:classes] += parent_info[:classes] parent_info[:parameters].each do |param, value| - # Specifically test for whether it's set, so false values are handled - # correctly. + # Specifically test for whether it's set, so false values are handled correctly. information[:parameters][param] = value unless information[:parameters].include?(param) end - information[:environment] ||= parent_info[:environment] parent_info[:parent] - else - raise Puppet::Error.new("Could not find parent node '#{parent}'") - nil - end - end # Take a name and a hash, and return a node instance. diff --git a/lib/puppet/indirector/node/memory.rb b/lib/puppet/indirector/node/memory.rb index ce4a52a8f..029926af8 100644 --- a/lib/puppet/indirector/node/memory.rb +++ b/lib/puppet/indirector/node/memory.rb @@ -3,7 +3,7 @@ require 'puppet/indirector/memory' class Puppet::Node::Memory < Puppet::Indirector::Memory desc "Keep track of nodes in memory but nowhere else. This is used for - one-time compiles, such as what the stand-alone ``puppet`` does. + one-time compiles, such as what the stand-alone `puppet` does. To use this terminus, you must load it with the data you want it to contain; it is only useful for developers and should generally not be chosen by a normal user." diff --git a/lib/puppet/indirector/report/yaml.rb b/lib/puppet/indirector/report/yaml.rb new file mode 100644 index 000000000..bf7bf4fe5 --- /dev/null +++ b/lib/puppet/indirector/report/yaml.rb @@ -0,0 +1,11 @@ +require 'puppet/transaction/report' +require 'puppet/indirector/yaml' + +class Puppet::Transaction::Report::Yaml < Puppet::Indirector::Yaml + desc "Store last report as a flat file, serialized using YAML." + + # Force report to be saved there + def path(name,ext='.yaml') + Puppet[:lastrunreport] + end +end diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb index c7c053f4b..23997e97a 100644 --- a/lib/puppet/indirector/yaml.rb +++ b/lib/puppet/indirector/yaml.rb @@ -41,19 +41,16 @@ class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus end end - # Get the yaml directory - def base - Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir] - end - # Return the path to a given node's file. - def path(name) - File.join(base, self.class.indirection_name.to_s, name.to_s + ".yaml") + def path(name,ext='.yaml') + base = Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir] + File.join(base, self.class.indirection_name.to_s, name.to_s + ext) end - # Do a glob on the yaml directory, loading each file found def search(request) - Dir.glob(File.join(base, self.class.indirection_name.to_s, request.key)).collect { |f| YAML.load_file(f) } + Dir.glob(path(request.key,'')).collect do |file| + YAML.load_file(file) + end end private diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/network/format_handler.rb index d378ad6a1..b94a4f902 100644 --- a/lib/puppet/network/format_handler.rb +++ b/lib/puppet/network/format_handler.rb @@ -37,6 +37,12 @@ module Puppet::Network::FormatHandler instance end + def self.create_serialized_formats(name,options = {},&block) + ["application/x-#{name}", "application/#{name}", "text/x-#{name}", "text/#{name}"].each { |mime_type| + create name, {:mime => mime_type}.update(options), &block + } + end + def self.extended(klass) klass.extend(ClassMethods) diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb index 8a61ee62a..4ca3240d4 100644 --- a/lib/puppet/network/formats.rb +++ b/lib/puppet/network/formats.rb @@ -1,6 +1,6 @@ require 'puppet/network/format_handler' -Puppet::Network::FormatHandler.create(:yaml, :mime => "text/yaml") do +Puppet::Network::FormatHandler.create_serialized_formats(:yaml) do # Yaml doesn't need the class name; it's serialized. def intern(klass, text) YAML.load(text) @@ -29,7 +29,7 @@ end # This is a "special" format which is used for the moment only when sending facts # as REST GET parameters (see Puppet::Configurer::FactHandler). # This format combines a yaml serialization, then zlib compression and base64 encoding. -Puppet::Network::FormatHandler.create(:b64_zlib_yaml, :mime => "text/b64_zlib_yaml") do +Puppet::Network::FormatHandler.create_serialized_formats(:b64_zlib_yaml) do require 'base64' def use_zlib? @@ -127,7 +127,7 @@ Puppet::Network::FormatHandler.create(:raw, :mime => "application/x-raw", :weigh end end -Puppet::Network::FormatHandler.create(:pson, :mime => "text/pson", :weight => 10, :required_methods => [:render_method, :intern_method]) do +Puppet::Network::FormatHandler.create_serialized_formats(:pson, :weight => 10, :required_methods => [:render_method, :intern_method]) do confine :true => Puppet.features.pson? def intern(klass, text) @@ -159,4 +159,4 @@ Puppet::Network::FormatHandler.create(:pson, :mime => "text/pson", :weight => 10 end # This is really only ever going to be used for Catalogs. -Puppet::Network::FormatHandler.create(:dot, :mime => "text/dot", :required_methods => [:render_method]) +Puppet::Network::FormatHandler.create_serialized_formats(:dot, :required_methods => [:render_method]) diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index 27b913ab9..9abc7ee1a 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -4,9 +4,13 @@ require 'webrick/httpstatus' require 'cgi' require 'delegate' require 'sync' +require 'xmlrpc/server' +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 diff --git a/lib/puppet/network/http/api/v1.rb b/lib/puppet/network/http/api/v1.rb index dd4612a14..abbb2dfa9 100644 --- a/lib/puppet/network/http/api/v1.rb +++ b/lib/puppet/network/http/api/v1.rb @@ -30,7 +30,7 @@ module Puppet::Network::HTTP::API::V1 key = URI.unescape(key) - Puppet::Indirector::Request.new(indirection, method, key, params) + [indirection, method, key, params] end def indirection2uri(request) @@ -57,9 +57,8 @@ module Puppet::Network::HTTP::API::V1 # fix to not need this, and our goal is to move away from the complication # that leads to the fix being too long. return :singular if indirection == "facts" - - # "status" really is singular return :singular if indirection == "status" + return :plural if indirection == "inventory" result = (indirection =~ /s$/) ? :plural : :singular diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb index 03d24b3fe..82238aa0a 100644 --- a/lib/puppet/network/http/handler.rb +++ b/lib/puppet/network/http/handler.rb @@ -61,11 +61,11 @@ module Puppet::Network::HTTP::Handler # handle an HTTP request def process(request, response) - indirection_request = uri2indirection(http_method(request), path(request), params(request)) + indirection, method, key, params = uri2indirection(http_method(request), path(request), params(request)) - check_authorization(indirection_request) + check_authorization(indirection, method, key, params) - send("do_#{indirection_request.method}", indirection_request, request, response) + send("do_#{method}", indirection, key, params, request, response) rescue SystemExit,NoMemoryError raise rescue Exception => e @@ -96,11 +96,16 @@ module Puppet::Network::HTTP::Handler set_response(response, exception.to_s, status) end + def model(indirection_name) + raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless indirection = Puppet::Indirector::Indirection.instance(indirection_name.to_sym) + indirection.model + end + # Execute our find. - def do_find(indirection_request, request, response) - unless result = indirection_request.model.find(indirection_request.key, indirection_request.to_hash) - Puppet.info("Could not find #{indirection_request.indirection_name} for '#{indirection_request.key}'") - return do_exception(response, "Could not find #{indirection_request.indirection_name} #{indirection_request.key}", 404) + def do_find(indirection_name, key, params, request, response) + unless result = model(indirection_name).find(key, params) + Puppet.info("Could not find #{indirection_name} for '#{key}'") + return do_exception(response, "Could not find #{indirection_name} #{key}", 404) end # The encoding of the result must include the format to use, @@ -113,34 +118,35 @@ module Puppet::Network::HTTP::Handler end # Execute our search. - def do_search(indirection_request, request, response) - result = indirection_request.model.search(indirection_request.key, indirection_request.to_hash) + def do_search(indirection_name, key, params, request, response) + model = self.model(indirection_name) + result = model.search(key, params) - if result.nil? or (result.is_a?(Array) and result.empty?) - return do_exception(response, "Could not find instances in #{indirection_request.indirection_name} with '#{indirection_request.to_hash.inspect}'", 404) + if result.nil? + return do_exception(response, "Could not find instances in #{indirection_name} with '#{key}'", 404) end format = format_to_use(request) set_content_type(response, format) - set_response(response, indirection_request.model.render_multiple(format, result)) + set_response(response, model.render_multiple(format, result)) end # Execute our destroy. - def do_destroy(indirection_request, request, response) - result = indirection_request.model.destroy(indirection_request.key, indirection_request.to_hash) + def do_destroy(indirection_name, key, params, request, response) + result = model(indirection_name).destroy(key, params) return_yaml_response(response, result) end # Execute our save. - def do_save(indirection_request, request, response) + def do_save(indirection_name, key, params, request, response) data = body(request).to_s raise ArgumentError, "No data to save" if !data or data.empty? format = request_format(request) - obj = indirection_request.model.convert_from(format, data) - result = save_object(indirection_request, obj) + obj = model(indirection_name).convert_from(format, data) + result = obj.save(key) return_yaml_response(response, result) end @@ -162,12 +168,6 @@ module Puppet::Network::HTTP::Handler set_response(response, body.to_yaml) end - # LAK:NOTE This has to be here for testing; it's a stub-point so - # we keep infinite recursion from happening. - def save_object(ind_request, object) - object.save(ind_request.key) - end - def get?(request) http_method(request) == 'GET' end diff --git a/lib/puppet/network/http/rack.rb b/lib/puppet/network/http/rack.rb index c18a07559..5b4ef7e1c 100644 --- a/lib/puppet/network/http/rack.rb +++ b/lib/puppet/network/http/rack.rb @@ -1,3 +1,6 @@ +require 'rack' +require 'rack/request' +require 'rack/response' require 'puppet/network/http' require 'puppet/network/http/rack/rest' diff --git a/lib/puppet/network/http/rack/rest.rb b/lib/puppet/network/http/rack/rest.rb index e5f50c465..b7e1d9709 100644 --- a/lib/puppet/network/http/rack/rest.rb +++ b/lib/puppet/network/http/rack/rest.rb @@ -41,7 +41,7 @@ class Puppet::Network::HTTP::RackREST < Puppet::Network::HTTP::RackHttpHandler unless result.is_a?(File) response.write result else - response["Content-Length"] = result.stat.size + response["Content-Length"] = result.stat.size.to_s response.body = RackFile.new(result) end end diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb index 91008aa1a..d5c146d88 100644 --- a/lib/puppet/network/http/webrick/rest.rb +++ b/lib/puppet/network/http/webrick/rest.rb @@ -1,5 +1,6 @@ require 'puppet/network/http/handler' require 'resolv' +require 'webrick' class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb index a3b055572..7d227b4d4 100644 --- a/lib/puppet/network/http_pool.rb +++ b/lib/puppet/network/http_pool.rb @@ -58,18 +58,6 @@ module Puppet::Network::HttpPool http.cert = ssl_host.certificate.content http.verify_mode = OpenSSL::SSL::VERIFY_PEER http.key = ssl_host.key.content - http.verify_callback = self.method(:ssl_verify_callback).to_proc if Puppet[:debug] - end - - def self.ssl_verify_callback(peer_ok, x509_store_ctx) - if not peer_ok - Puppet.debug "OpenSSL: Error(#{x509_store_ctx.error}): #{x509_store_ctx.error_string}" - Puppet.debug "OpenSSL: Cert: #{x509_store_ctx.current_cert.issuer}" - Puppet.debug "OpenSSL: Current CRL: #{x509_store_ctx.current_crl}" - Puppet.debug "OpenSSL: Chain:" - x509_store_ctx.chain.each_index { |i| Puppet.debug "OpenSSL: \t#{i} #{x509_store_ctx.chain[i].issuer}" } - end - peer_ok end # Retrieve a cached http instance if caching is enabled, else return diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb index 38a8f9a09..b6a163316 100644 --- a/lib/puppet/network/rest_authconfig.rb +++ b/lib/puppet/network/rest_authconfig.rb @@ -3,6 +3,7 @@ require 'puppet/network/authconfig' module Puppet class Network::RestAuthConfig < Network::AuthConfig + extend MonitorMixin attr_accessor :rights DEFAULT_ACL = [ @@ -20,30 +21,32 @@ module Puppet ] def self.main - add_acl = @main.nil? - super - @main.insert_default_acl if add_acl and !@main.exists? + synchronize do + add_acl = @main.nil? + super + @main.insert_default_acl if add_acl and !@main.exists? + end @main end # check wether this request is allowed in our ACL # raise an Puppet::Network::AuthorizedError if the request # is denied. - def allowed?(request) + def allowed?(indirection, method, key, params) read # we're splitting the request in part because # fail_on_deny could as well be called in the XMLRPC context # with a ClientRequest. - @rights.fail_on_deny( - build_uri(request), - - :node => request.node, - :ip => request.ip, - :method => request.method, - :environment => request.environment, - :authenticated => request.authenticated) + @rights.fail_on_deny( + build_uri(indirection, key), + :node => params[:node], + :ip => params[:ip], + :method => method, + :environment => params[:environment], + :authenticated => params[:authenticated] + ) end def initialize(file = nil, parsenow = true) @@ -87,8 +90,8 @@ module Puppet @rights.restrict_authenticated(acl[:acl], acl[:authenticated]) unless acl[:authenticated].nil? end - def build_uri(request) - "/#{request.indirection_name}/#{request.key}" + def build_uri(indirection_name, key) + "/#{indirection_name}/#{key}" end end end diff --git a/lib/puppet/network/rest_authorization.rb b/lib/puppet/network/rest_authorization.rb index e052245eb..50f094e3e 100644 --- a/lib/puppet/network/rest_authorization.rb +++ b/lib/puppet/network/rest_authorization.rb @@ -15,8 +15,8 @@ module Puppet::Network end # Verify that our client has access. - def check_authorization(request) - authconfig.allowed?(request) + def check_authorization(indirection, method, key, params) + authconfig.allowed?(indirection, method, key, params) end end end diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb index d424b9c4a..e4de07dea 100644 --- a/lib/puppet/network/server.rb +++ b/lib/puppet/network/server.rb @@ -32,14 +32,14 @@ class Puppet::Network::Server # Create a pidfile for our daemon, so we can be stopped and others # don't try to start. def create_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock end end # Remove the pid file for our daemon. def remove_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do locker = Puppet::Util::Pidlock.new(pidfile) locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked? end diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb index 2453cd1d5..e8d58e6be 100644 --- a/lib/puppet/node.rb +++ b/lib/puppet/node.rb @@ -3,6 +3,7 @@ require 'puppet/indirector' # A class for managing nodes, including their facts and environment. class Puppet::Node require 'puppet/node/facts' + require 'puppet/node/inventory' require 'puppet/node/environment' # Set up indirection, so that nodes can be looked for in diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index 762599cff..7877b7f73 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -1,4 +1,5 @@ require 'puppet/util/cacher' +require 'monitor' # Just define it, so this class has fewer load dependencies. class Puppet::Node @@ -67,14 +68,23 @@ class Puppet::Node::Environment def initialize(name) @name = name + extend MonitorMixin end def known_resource_types - if @known_resource_types.nil? or @known_resource_types.stale? - @known_resource_types = Puppet::Resource::TypeCollection.new(self) - @known_resource_types.perform_initial_import - end - @known_resource_types + # This makes use of short circuit evaluation to get the right thread-safe + # per environment semantics with an efficient most common cases; we almost + # always just return our thread's known-resource types. Only at the start + # of a compilation (after our thread var has been set to nil) or when the + # environment has changed do we delve deeper. + Thread.current[:known_resource_types] = nil if (krt = Thread.current[:known_resource_types]) && krt.environment != self + Thread.current[:known_resource_types] ||= synchronize { + if @known_resource_types.nil? or @known_resource_types.stale? + @known_resource_types = Puppet::Resource::TypeCollection.new(self) + @known_resource_types.import_ast(perform_initial_import, '') + end + @known_resource_types + } end def module(name) @@ -114,6 +124,10 @@ class Puppet::Node::Environment name.to_s end + def to_sym + to_s.to_sym + end + # The only thing we care about when serializing an environment is its # identity; everything else is ephemeral and should not be stored or # transmitted. @@ -133,5 +147,31 @@ class Puppet::Node::Environment end end + private + + def perform_initial_import + return empty_parse_result if Puppet.settings[:ignoreimport] + parser = Puppet::Parser::Parser.new(self) + if code = Puppet.settings.uninterpolated_value(:code, name.to_s) and code != "" + parser.string = code + else + file = Puppet.settings.value(:manifest, name.to_s) + return empty_parse_result unless File.exist?(file) + parser.file = file + end + parser.parse + rescue => detail + msg = "Could not parse for environment #{self}: #{detail}" + error = Puppet::Error.new(msg) + error.set_backtrace(detail.backtrace) + raise error + end + + def empty_parse_result + # Return an empty toplevel hostclass to use as the result of + # perform_initial_import when no file was actually loaded. + return Puppet::Parser::AST::Hostclass.new('') + end + @root = new(:'*root*') end diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb index b77ad22d5..d84d54113 100755 --- a/lib/puppet/node/facts.rb +++ b/lib/puppet/node/facts.rb @@ -1,12 +1,17 @@ +require 'time' + require 'puppet/node' require 'puppet/indirector' +require 'puppet/util/pson' + # Manage a given node's facts. This either accepts facts and stores them, or # returns facts for a given node. class Puppet::Node::Facts # Set up indirection, so that nodes can be looked for in # the node sources. extend Puppet::Indirector + extend Puppet::Util::Pson # We want to expire any cached nodes if the facts are saved. module NodeExpirer @@ -30,7 +35,7 @@ class Puppet::Node::Facts @name = name @values = values - add_internal + add_timestamp end def downcase_if_necessary @@ -54,13 +59,37 @@ class Puppet::Node::Facts strip_internal == other.send(:strip_internal) end - private + def self.from_pson(data) + result = new(data['name'], data['values']) + result.values[:_timestamp] = Time.parse(data['timestamp']) + result.expiration = Time.parse(data['expiration']) + result + end + + def to_pson(*args) + { + 'expiration' => expiration, + 'name' => name, + 'timestamp' => values[:_timestamp], + 'values' => values.reject {|k,v| k == :_timestamp}, + }.to_pson(*args) + end # Add internal data to the facts for storage. - def add_internal - self.values[:_timestamp] = Time.now + def add_timestamp + self.timestamp = Time.now end + def timestamp=(time) + self.values[:_timestamp] = time + end + + def timestamp + self.values[:_timestamp] + end + + private + # Strip out that internal data. def strip_internal newvals = values.dup diff --git a/lib/puppet/node/inventory.rb b/lib/puppet/node/inventory.rb new file mode 100644 index 000000000..fd99163b0 --- /dev/null +++ b/lib/puppet/node/inventory.rb @@ -0,0 +1,7 @@ +require 'puppet/node' +require 'puppet/indirector' + +class Puppet::Node::Inventory + extend Puppet::Indirector + indirects :inventory, :terminus_setting => :inventory_terminus +end diff --git a/lib/puppet/parameter/value_collection.rb b/lib/puppet/parameter/value_collection.rb index a9fd20233..619e0731d 100644 --- a/lib/puppet/parameter/value_collection.rb +++ b/lib/puppet/parameter/value_collection.rb @@ -21,14 +21,14 @@ class Puppet::Parameter::ValueCollection @doc += " Valid values are " @doc += @strings.collect do |value| if aliases = value.aliases and ! aliases.empty? - "``#{value.name}`` (also called ``#{aliases.join(", ")}``)" + "`#{value.name}` (also called `#{aliases.join(", ")}`)" else - "``#{value.name}``" + "`#{value.name}`" end end.join(", ") + "." end - @doc += " Values can match ``" + regexes.join("``, ``") + "``." unless regexes.empty? + @doc += " Values can match `" + regexes.join("`, `") + "`." unless regexes.empty? end @doc diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index 54e034acb..03891160b 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -107,28 +107,32 @@ end require 'puppet/parser/ast/arithmetic_operator' require 'puppet/parser/ast/astarray' require 'puppet/parser/ast/asthash' -require 'puppet/parser/ast/branch' require 'puppet/parser/ast/boolean_operator' +require 'puppet/parser/ast/branch' require 'puppet/parser/ast/caseopt' require 'puppet/parser/ast/casestatement' require 'puppet/parser/ast/collection' require 'puppet/parser/ast/collexpr' require 'puppet/parser/ast/comparison_operator' +require 'puppet/parser/ast/definition' require 'puppet/parser/ast/else' require 'puppet/parser/ast/function' +require 'puppet/parser/ast/hostclass' require 'puppet/parser/ast/ifstatement' require 'puppet/parser/ast/in_operator' require 'puppet/parser/ast/leaf' require 'puppet/parser/ast/match_operator' require 'puppet/parser/ast/minus' +require 'puppet/parser/ast/node' require 'puppet/parser/ast/nop' require 'puppet/parser/ast/not' +require 'puppet/parser/ast/relationship' require 'puppet/parser/ast/resource' require 'puppet/parser/ast/resource_defaults' +require 'puppet/parser/ast/resource_instance' require 'puppet/parser/ast/resource_override' require 'puppet/parser/ast/resource_reference' require 'puppet/parser/ast/resourceparam' require 'puppet/parser/ast/selector' require 'puppet/parser/ast/tag' require 'puppet/parser/ast/vardef' -require 'puppet/parser/ast/relationship' diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 529998e3c..7283a1f6c 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -16,25 +16,20 @@ class Puppet::Parser::AST # Evaluate our children. def evaluate(scope) - # Make a new array, so we don't have to deal with the details of - # flattening and such - items = [] - - # First clean out any AST::ASTArrays - @children.each { |child| - if child.instance_of?(AST::ASTArray) - child.each do |ac| - items << ac + result = [] + @children.each do |child| + # Skip things that respond to :instantiate (classes, nodes, + # and definitions), because they have already been + # instantiated. + if !child.respond_to?(:instantiate) + item = child.safeevaluate(scope) + if !item.nil? + # nil values are implicitly removed. + result.push(item) end - else - items << child end - } - - rets = items.flatten.collect { |child| - child.safeevaluate(scope) - } - rets.reject { |o| o.nil? } + end + result end def push(*ary) @@ -52,10 +47,4 @@ class Puppet::Parser::AST "[" + @children.collect { |c| c.to_s }.join(', ') + "]" end end - - # A simple container class, containing the parameters for an object. - # Used for abstracting the grammar declarations. Basically unnecessary - # except that I kept finding bugs because I had too many arrays that - # meant completely different things. - class ResourceInstance < ASTArray; end end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb index 4e296e82f..db4c2b024 100644 --- a/lib/puppet/parser/ast/caseopt.rb +++ b/lib/puppet/parser/ast/caseopt.rb @@ -18,16 +18,12 @@ class Puppet::Parser::AST # Cache the @default value. return @default if defined?(@default) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - if subval.is_a?(AST::Default) - @default = true - break - end - } - else - @default = true if @value.is_a?(AST::Default) - end + @value.each { |subval| + if subval.is_a?(AST::Default) + @default = true + break + end + } @default ||= false @@ -36,23 +32,15 @@ class Puppet::Parser::AST # You can specify a list of values; return each in turn. def eachvalue(scope) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval.safeevaluate(scope) - } - else - yield @value.safeevaluate(scope) - end + @value.each { |subval| + yield subval.safeevaluate(scope) + } end def eachopt - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval - } - else - yield @value - end + @value.each { |subval| + yield subval + } end # Evaluate the actual statements; this only gets called if diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index 09d5b4eb3..ef36b7143 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -5,61 +5,44 @@ require 'puppet/parser/collector' # An object that collects stored objects from the central cache and returns # them to the current host, yo. class Puppet::Parser::AST -class Collection < AST::Branch - attr_accessor :type, :query, :form - attr_reader :override - - associates_doc - - # We return an object that does a late-binding evaluation. - def evaluate(scope) - if self.query - str, code = self.query.safeevaluate scope - else - str = code = nil - end - - newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form) - - scope.compiler.add_collection(newcoll) - - # overrides if any - # Evaluate all of the specified params. - if @override - params = @override.collect do |param| - param.safeevaluate(scope) + class Collection < AST::Branch + attr_accessor :type, :query, :form + attr_reader :override + + associates_doc + + # We return an object that does a late-binding evaluation. + def evaluate(scope) + str, code = query && query.safeevaluate(scope) + + resource_type = scope.find_resource_type(@type) + newcoll = Puppet::Parser::Collector.new(scope, resource_type.name, str, code, self.form) + + scope.compiler.add_collection(newcoll) + + # overrides if any + # Evaluate all of the specified params. + if @override + params = @override.collect { |param| param.safeevaluate(scope) } + newcoll.add_override( + :parameters => params, + :file => @file, + :line => @line, + :source => scope.source, + :scope => scope + ) end - - newcoll.add_override( - - :parameters => params, - :file => @file, - :line => @line, - :source => scope.source, - - :scope => scope - ) + newcoll end - newcoll - end - - # Handle our parameter ourselves - def override=(override) - if override.is_a?(AST::ASTArray) - @override = override - else - - @override = AST::ASTArray.new( - - :line => override.line, - :file => override.file, - - :children => [override] - ) + # Handle our parameter ourselves + def override=(override) + @override = if override.is_a?(AST::ASTArray) + override + else + AST::ASTArray.new(:line => override.line,:file => override.file,:children => [override]) + end end end - -end end diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb new file mode 100644 index 000000000..c43422f82 --- /dev/null +++ b/lib/puppet/parser/ast/definition.rb @@ -0,0 +1,17 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Definition < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :context + + def initialize(name, context = {}, &ruby_code) + @name = name + @context = context + @ruby_code = ruby_code + end + + def instantiate(modname) + new_definition = Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname)) + new_definition.ruby_code = @ruby_code if @ruby_code + [new_definition] + end +end diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb index 602016c75..80e6e6512 100644 --- a/lib/puppet/parser/ast/function.rb +++ b/lib/puppet/parser/ast/function.rb @@ -11,7 +11,6 @@ class Puppet::Parser::AST @settor = true def evaluate(scope) - # Make sure it's a defined function raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name) @@ -29,7 +28,7 @@ class Puppet::Parser::AST end # We don't need to evaluate the name, because it's plaintext - args = @arguments.safeevaluate(scope) + args = @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x } scope.send("function_#{@name}", args) end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb new file mode 100644 index 000000000..cab5e4a24 --- /dev/null +++ b/lib/puppet/parser/ast/hostclass.rb @@ -0,0 +1,29 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Hostclass < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :name, :context + + def initialize(name, context = {}, &ruby_code) + @context = context + @name = name + @ruby_code = ruby_code + end + + def instantiate(modname) + new_class = Puppet::Resource::Type.new(:hostclass, @name, @context.merge(:module_name => modname)) + new_class.ruby_code = @ruby_code if @ruby_code + all_types = [new_class] + if code + code.each do |nested_ast_node| + if nested_ast_node.respond_to? :instantiate + all_types += nested_ast_node.instantiate(modname) + end + end + end + return all_types + end + + def code() + @context[:code] + end +end diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 49cde63ca..fcdd219d7 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -42,7 +42,7 @@ class Puppet::Parser::AST # The base string class. class String < AST::Leaf def evaluate(scope) - @value + @value.dup end def to_s @@ -148,12 +148,20 @@ class Puppet::Parser::AST key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key end + def array_index_or_key(object, key) + if object.is_a?(Array) + raise Puppet::ParserError, "#{key} is not an integer, but is used as an index of an array" unless key = Puppet::Parser::Scope.number?(key) + end + key + end + def evaluate(scope) object = evaluate_container(scope) + accesskey = evaluate_key(scope) raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array) - object[evaluate_key(scope)] + object[array_index_or_key(object, accesskey)] end # Assign value to this hashkey or array index @@ -166,7 +174,7 @@ class Puppet::Parser::AST end # assign to hash or array - object[accesskey] = value + object[array_index_or_key(object, accesskey)] = value end def to_s diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb new file mode 100644 index 000000000..b69a5c4e0 --- /dev/null +++ b/lib/puppet/parser/ast/node.rb @@ -0,0 +1,20 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Node < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :names, :context + + def initialize(names, context = {}, &ruby_code) + raise ArgumentError, "names should be an array" unless names.is_a? Array + @names = names + @context = context + @ruby_code = ruby_code + end + + def instantiate(modname) + @names.collect do |name| + new_node = Puppet::Resource::Type.new(:node, name, @context.merge(:module_name => modname)) + new_node.ruby_code = @ruby_code if @ruby_code + new_node + end + end +end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 1b063c984..ce3c499c5 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -3,26 +3,15 @@ require 'puppet/parser/ast/resource_reference' # Any normal puppet resource declaration. Can point to a definition or a # builtin type. class Puppet::Parser::AST -class Resource < AST::ResourceReference +class Resource < AST::Branch associates_doc - attr_accessor :title, :type, :exported, :virtual - attr_reader :parameters + attr_accessor :type, :instances, :exported, :virtual # Does not actually return an object; instead sets an object # in the current scope. def evaluate(scope) - # Evaluate all of the specified params. - paramobjects = parameters.collect { |param| - param.safeevaluate(scope) - } - - resource_titles = @title.safeevaluate(scope) - - # it's easier to always use an array, even for only one name - resource_titles = [resource_titles] unless resource_titles.is_a?(Array) - # We want virtual to be true if exported is true. We can't # just set :virtual => self.virtual in the initialization, # because sometimes the :virtual attribute is set *after* @@ -30,48 +19,49 @@ class Resource < AST::ResourceReference # is true. Argh, this was a very tough one to track down. virt = self.virtual || self.exported - # This is where our implicit iteration takes place; if someone - # passed an array as the name, then we act just like the called us - # many times. - resource_titles.flatten.collect { |resource_title| - exceptwrap :type => Puppet::ParseError do + # First level of implicit iteration: build a resource for each + # instance. This handles things like: + # file { '/foo': owner => blah; '/bar': owner => blah } + @instances.collect { |instance| - resource = Puppet::Parser::Resource.new( - type, resource_title, - :parameters => paramobjects, - :file => self.file, - :line => self.line, - :exported => self.exported, - :virtual => virt, - :source => scope.source, - :scope => scope, - - :strict => true - ) + # Evaluate all of the specified params. + paramobjects = instance.parameters.collect { |param| + param.safeevaluate(scope) + } - # And then store the resource in the compiler. - # At some point, we need to switch all of this to return - # resources instead of storing them like this. - scope.compiler.add_resource(scope, resource) - resource - end - }.reject { |resource| resource.nil? } - end + resource_titles = instance.title.safeevaluate(scope) + + # it's easier to always use an array, even for only one name + resource_titles = [resource_titles] unless resource_titles.is_a?(Array) + + fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles) - # Set the parameters for our object. - def parameters=(params) - if params.is_a?(AST::ASTArray) - @parameters = params - else + # Second level of implicit iteration; build a resource for each + # title. This handles things like: + # file { ['/foo', '/bar']: owner => blah } + resource_titles.flatten.collect { |resource_title| + exceptwrap :type => Puppet::ParseError do + resource = Puppet::Parser::Resource.new( + fully_qualified_type, resource_title, + :parameters => paramobjects, + :file => self.file, + :line => self.line, + :exported => self.exported, + :virtual => virt, + :source => scope.source, + :scope => scope, + :strict => true + ) - @parameters = AST::ASTArray.new( - - :line => params.line, - :file => params.file, - - :children => [params] - ) - end + if resource.resource_type.is_a? Puppet::Resource::Type + resource.resource_type.instantiate_resource(scope, resource) + end + scope.compiler.add_resource(scope, resource) + scope.compiler.evaluate_classes([resource_title],scope,false) if fully_qualified_type == 'class' + resource + end + } + }.flatten.reject { |resource| resource.nil? } end end end diff --git a/lib/puppet/parser/ast/resource_instance.rb b/lib/puppet/parser/ast/resource_instance.rb new file mode 100644 index 000000000..ebfb17bf1 --- /dev/null +++ b/lib/puppet/parser/ast/resource_instance.rb @@ -0,0 +1,9 @@ +require 'puppet/parser/ast/branch' + +class Puppet::Parser::AST + class ResourceInstance < Branch + # A simple container for a parameter for an object. Consists of a + # title and a set of parameters. + attr_accessor :title, :parameters + end +end diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index e0be889ff..d638202ab 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -3,12 +3,11 @@ require 'puppet/parser/ast/resource' class Puppet::Parser::AST # Set a parameter on a resource specification created somewhere else in the # configuration. The object is responsible for verifying that this is allowed. - class ResourceOverride < Resource + class ResourceOverride < AST::Branch associates_doc - attr_accessor :object - attr_reader :parameters + attr_accessor :object, :parameters # Iterate across all of our children. def each diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb index 5d8334335..0f8e655bf 100644 --- a/lib/puppet/parser/ast/resource_reference.rb +++ b/lib/puppet/parser/ast/resource_reference.rb @@ -7,8 +7,15 @@ class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch # Evaluate our object, but just return a simple array of the type # and name. def evaluate(scope) - titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) } - return(titles.length == 1 ? titles.pop : titles) + titles = Array(title.safeevaluate(scope)) + + a_type, titles = scope.resolve_type_and_titles(type, titles) + + resources = titles.collect{ |a_title| + Puppet::Resource.new(a_type, a_title) + } + + return(resources.length == 1 ? resources.pop : resources) end def to_s diff --git a/lib/puppet/parser/ast/top_level_construct.rb b/lib/puppet/parser/ast/top_level_construct.rb new file mode 100644 index 000000000..901a939c2 --- /dev/null +++ b/lib/puppet/parser/ast/top_level_construct.rb @@ -0,0 +1,4 @@ +# The base class for AST nodes representing top level things: +# hostclasses, definitions, and nodes. +class Puppet::Parser::AST::TopLevelConstruct < Puppet::Parser::AST +end diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index a901c0dd6..c60e1d4fb 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -19,7 +19,12 @@ class Puppet::Parser::Compiler rescue => detail puts detail.backtrace if Puppet[:trace] raise Puppet::Error, "#{detail} on node #{node.name}" - end + ensure + # We get these from the environment and only cache them in a thread + # variable for the duration of the compilation. + Thread.current[:known_resource_types] = nil + Thread.current[:env_module_directories] = nil + end attr_reader :node, :facts, :collections, :catalog, :node_scope, :resources, :relationships @@ -51,13 +56,10 @@ class Puppet::Parser::Compiler # Note that this will fail if the resource is not unique. @catalog.add_resource(resource) - set_container_resource(scope, resource) - end - # Add our container edge. If we're a class, then we get treated specially - we can - # control the stage that the class is applied in. Otherwise, we just - # get added to our parent container. - def set_container_resource(scope, resource) + # Add our container edge. If we're a class, then we get treated specially - we can + # control the stage that the class is applied in. Otherwise, we just + # get added to our parent container. return if resource.type.to_s.downcase == "stage" if resource.type.to_s.downcase != "class" @@ -65,15 +67,14 @@ class Puppet::Parser::Compiler return @catalog.add_edge(scope.resource, resource) end - unless stage = @catalog.resource(:stage, resource[:stage] || :main) + unless stage = @catalog.resource(:stage, resource[:stage] || (scope && scope.resource && scope.resource[:stage]) || :main) raise ArgumentError, "Could not find stage #{resource[:stage] || :main} specified by #{resource}" end + resource[:stage] ||= stage.title unless stage.title == :main @catalog.add_edge(stage, resource) end - private :set_container_resource - # Do we use nodes found in the code, vs. the external node sources? def ast_nodes? known_resource_types.nodes? @@ -143,7 +144,7 @@ class Puppet::Parser::Compiler if klass = scope.find_hostclass(name) found << name and next if scope.class_scope(klass) - resource = klass.mk_plain_resource(scope) + resource = klass.ensure_in_catalog(scope) # If they've disabled lazy evaluation (which the :include function does), # then evaluate our resource immediately. @@ -219,7 +220,7 @@ class Puppet::Parser::Compiler # Create a resource to model this node, and then add it to the list # of resources. - resource = astnode.mk_plain_resource(topscope) + resource = astnode.ensure_in_catalog(topscope) resource.evaluate @@ -284,10 +285,7 @@ class Puppet::Parser::Compiler @main_resource = Puppet::Parser::Resource.new("class", :main, :scope => @topscope, :source => @main) @topscope.resource = @main_resource - @resources << @main_resource - @catalog.add_resource(@main_resource) - - set_container_resource(@topscope, @main_resource) + add_resource(@topscope, @main_resource) @main_resource.evaluate end diff --git a/lib/puppet/parser/files.rb b/lib/puppet/parser/files.rb index 9ef05e102..f34683153 100644 --- a/lib/puppet/parser/files.rb +++ b/lib/puppet/parser/files.rb @@ -24,7 +24,7 @@ module Puppet::Parser::Files # Than that would be a "no." end abspat = File::expand_path(start, cwd) - [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{,.pp,.rb}' : '' )).uniq.reject { |f| FileTest.directory?(f) }] + [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{.pp,.rb}' : '' )).uniq.reject { |f| FileTest.directory?(f) }] end # Find the concrete file denoted by +file+. If +file+ is absolute, diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index c238da5d4..5807c0bbe 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -20,7 +20,7 @@ module Puppet::Parser::Functions @autoloader = Puppet::Util::Autoload.new( self, "puppet/parser/functions", - + :wrap => false ) end @@ -73,8 +73,10 @@ module Puppet::Parser::Functions def self.function(name) name = symbolize(name) - unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name) - autoloader.load(name,Environment.current || Environment.root) + @functions.synchronize do + unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name) + autoloader.load(name,Environment.current || Environment.root) + end end ( functions(Environment.root)[name] || functions[name] || {:name => false} )[:name] @@ -94,7 +96,7 @@ module Puppet::Parser::Functions ret += "Undocumented.\n" end - ret += "\n\n- **Type**: #{hash[:type]}\n\n" + ret += "\n\n- *Type*: #{hash[:type]}\n\n" end ret diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb index 2930a65cc..90632af2f 100644 --- a/lib/puppet/parser/functions/defined.rb +++ b/lib/puppet/parser/functions/defined.rb @@ -3,7 +3,7 @@ Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Dete type is defined, either as a native type or a defined type, or whether a class is defined. This is useful for checking whether a class is defined and only including it if it is. This function can also test whether a resource has been defined, using resource references - (e.g., ``if defined(File['/tmp/myfile']) { ... }``). This function is unfortunately + (e.g., `if defined(File['/tmp/myfile']) { ... }`). This function is unfortunately dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals| result = false vals = [vals] unless vals.is_a?(Array) diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb new file mode 100644 index 000000000..bc55410b9 --- /dev/null +++ b/lib/puppet/parser/functions/extlookup.rb @@ -0,0 +1,157 @@ +require 'csv' + +module Puppet::Parser::Functions + newfunction(:extlookup, + :type => :rvalue, + :doc => "This is a parser function to read data from external files, this version +uses CSV files but the concept can easily be adjust for databases, yaml +or any other queryable data source. + +The object of this is to make it obvious when it's being used, rather than +magically loading data in when an module is loaded I prefer to look at the code +and see statements like: + + $snmp_contact = extlookup(\"snmp_contact\") + +The above snippet will load the snmp_contact value from CSV files, this in its +own is useful but a common construct in puppet manifests is something like this: + + case $domain { + \"myclient.com\": { $snmp_contact = \"John Doe <john@myclient.com>\" } + default: { $snmp_contact = \"My Support <support@my.com>\" } + } + +Over time there will be a lot of this kind of thing spread all over your manifests +and adding an additional client involves grepping through manifests to find all the +places where you have constructs like this. + +This is a data problem and shouldn't be handled in code, a using this function you +can do just that. + +First you configure it in site.pp: + + $extlookup_datadir = \"/etc/puppet/manifests/extdata\" + $extlookup_precedence = [\"%{fqdn}\", \"domain_%{domain}\", \"common\"] + +The array tells the code how to resolve values, first it will try to find it in +web1.myclient.com.csv then in domain_myclient.com.csv and finally in common.csv + +Now create the following data files in /etc/puppet/manifests/extdata: + + domain_myclient.com.csv: + snmp_contact,John Doe <john@myclient.com> + root_contact,support@%{domain} + client_trusted_ips,192.168.1.130,192.168.10.0/24 + + common.csv: + snmp_contact,My Support <support@my.com> + root_contact,support@my.com + +Now you can replace the case statement with the simple single line to achieve +the exact same outcome: + + $snmp_contact = extlookup(\"snmp_contact\") + +The above code shows some other features, you can use any fact or variable that +is in scope by simply using %{varname} in your data files, you can return arrays +by just having multiple values in the csv after the initial variable name. + +In the event that a variable is nowhere to be found a critical error will be raised +that will prevent your manifest from compiling, this is to avoid accidentally putting +in empty values etc. You can however specify a default value: + + $ntp_servers = extlookup(\"ntp_servers\", \"1.${country}.pool.ntp.org\") + +In this case it will default to \"1.${country}.pool.ntp.org\" if nothing is defined in +any data file. + +You can also specify an additional data file to search first before any others at use +time, for example: + + $version = extlookup(\"rsyslog_version\", \"present\", \"packages\") + package{\"rsyslog\": ensure => $version } + +This will look for a version configured in packages.csv and then in the rest as configured +by $extlookup_precedence if it's not found anywhere it will default to `present`, this kind +of use case makes puppet a lot nicer for managing large amounts of packages since you do not +need to edit a load of manifests to do simple things like adjust a desired version number. + +Precedence values can have variables embedded in them in the form %{fqdn}, you could for example do: + + $extlookup_precedence = [\"hosts/%{fqdn}\", \"common\"] + +This will result in /path/to/extdata/hosts/your.box.com.csv being searched. + +This is for back compatibility to interpolate variables with %. % interpolation is a workaround for a problem that has been fixed: Puppet variable interpolation at top scope used to only happen on each run.") do |args| + + key = args[0] + + default = args[1] + datafile = args[2] + + raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3 + + extlookup_datadir = lookupvar('extlookup_datadir') + extlookup_precedence = Array.new + + extlookup_precedence = lookupvar('extlookup_precedence').collect do |var| + var.gsub(/%\{(.+?)\}/) do |capture| + lookupvar($1) + end + end + + datafiles = Array.new + + # if we got a custom data file, put it first in the array of search files + if datafile != "" + datafiles << extlookup_datadir + "/#{datafile}.csv" if File.exists?(extlookup_datadir + "/#{datafile}.csv") + end + + extlookup_precedence.each do |d| + datafiles << extlookup_datadir + "/#{d}.csv" + end + + desired = nil + + datafiles.each do |file| + if desired.nil? + if File.exists?(file) + result = CSV.read(file).find_all do |r| + r[0] == key + end + + # return just the single result if theres just one, + # else take all the fields in the csv and build an array + if result.length > 0 + if result[0].length == 2 + val = result[0][1].to_s + + # parse %{}'s in the CSV into local variables using lookupvar() + while val =~ /%\{(.+?)\}/ + val.gsub!(/%\{#{$1}\}/, lookupvar($1)) + end + + desired = val + elsif result[0].length > 1 + length = result[0].length + cells = result[0][1,length] + + # Individual cells in a CSV result are a weird data type and throws + # puppets yaml parsing, so just map it all to plain old strings + desired = cells.map do |c| + # parse %{}'s in the CSV into local variables using lookupvar() + while c =~ /%\{(.+?)\}/ + c.gsub!(/%\{#{$1}\}/, lookupvar($1)) + end + + c.to_s + end + end + end + end + end + end + + desired || default or raise Puppet::ParseError, "No match found for '#{key}' in any data file during extlookup()" + end +end diff --git a/lib/puppet/parser/functions/file.rb b/lib/puppet/parser/functions/file.rb index 963111260..19ab9ba2e 100644 --- a/lib/puppet/parser/functions/file.rb +++ b/lib/puppet/parser/functions/file.rb @@ -2,7 +2,7 @@ Puppet::Parser::Functions::newfunction( :file, :type => :rvalue, - + :doc => "Return the contents of a file. Multiple files can be passed, and the first file that exists will be read in.") do |vals| ret = nil diff --git a/lib/puppet/parser/functions/inline_template.rb b/lib/puppet/parser/functions/inline_template.rb index 46e000383..9759ff6e1 100644 --- a/lib/puppet/parser/functions/inline_template.rb +++ b/lib/puppet/parser/functions/inline_template.rb @@ -1,9 +1,10 @@ Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :doc => - "Evaluate a template string and return its value. See `the templating docs - <http://docs.puppetlabs.com/guides/templating.html>`_ for more information. Note that - if multiple template strings are specified, their output is all concatenated - and returned as the output of the function.") do |vals| - require 'erb' + "Evaluate a template string and return its value. See + [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for + more information. Note that if multiple template strings are specified, their + output is all concatenated and returned as the output of the function.") do |vals| + + require 'erb' vals.collect do |string| # Use a wrapper, so the template can't get access to the full diff --git a/lib/puppet/parser/functions/md5.rb b/lib/puppet/parser/functions/md5.rb new file mode 100644 index 000000000..f7a4f7222 --- /dev/null +++ b/lib/puppet/parser/functions/md5.rb @@ -0,0 +1,5 @@ +Puppet::Parser::Functions::newfunction(:md5, :type => :rvalue, :doc => "Returns a MD5 hash value from a provided string.") do |args| + require 'md5' + + Digest::MD5.hexdigest(args[0]) +end diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb index 4247b8af8..c21ccd14a 100644 --- a/lib/puppet/parser/functions/realize.rb +++ b/lib/puppet/parser/functions/realize.rb @@ -5,7 +5,7 @@ Puppet::Parser::Functions::newfunction(:realize, :doc => "Make a virtual object when you want to know the name of the virtual object and don't want to bother with a full collection. It is slightly faster than a collection, and, of course, is a bit shorter. You must pass the object using a - reference; e.g.: ``realize User[luke]``." ) do |vals| + reference; e.g.: `realize User[luke]`." ) do |vals| coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual) vals = [vals] unless vals.is_a?(Array) coll.resources = vals.flatten diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb index c0aeef222..f655db7b3 100644 --- a/lib/puppet/parser/functions/regsubst.rb +++ b/lib/puppet/parser/functions/regsubst.rb @@ -6,37 +6,37 @@ module Puppet::Parser::Functions :doc => " Perform regexp replacement on a string or array of strings. -- **Parameters** (in order): +* *Parameters* (in order): -:target: The string or array of strings to operate on. If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array. + _target_ The string or array of strings to operate on. If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array. -:regexp: The regular expression matching the target string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself. + _regexp_ The regular expression matching the target string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself. -:replacement: Replacement string. Can contain back references to what was matched using \\0, \\1, and so on. + _replacement_ Replacement string. Can contain back references to what was matched using \\0, \\1, and so on. -:flags: Optional. String of single letter flags for how the regexp is interpreted: + _flags_ Optional. String of single letter flags for how the regexp is interpreted: - - **E** Extended regexps - - **I** Ignore case in regexps - - **M** Multiline regexps - - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced. + - *E* Extended regexps + - *I* Ignore case in regexps + - *M* Multiline regexps + - *G* Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced. -:lang: Optional. How to handle multibyte characters. A single-character string with the following values: + _lang_ Optional. How to handle multibyte characters. A single-character string with the following values: - - **N** None - - **E** EUC - - **S** SJIS - - **U** UTF-8 + - *N* None + - *E* EUC + - *S* SJIS + - *U* UTF-8 -- **Examples** +* *Examples* -Get the third octet from the node's IP address:: +Get the third octet from the node's IP address: - $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3') + $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3') -Put angle brackets around each octet in the node's IP address:: +Put angle brackets around each octet in the node's IP address: - $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G') + $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G') ") \ do |args| unless args.length.between?(3, 5) diff --git a/lib/puppet/parser/functions/require.rb b/lib/puppet/parser/functions/require.rb index 3f98c9523..64285307e 100644 --- a/lib/puppet/parser/functions/require.rb +++ b/lib/puppet/parser/functions/require.rb @@ -12,9 +12,8 @@ relationships between classes. This function is a superset of the class depends on the required class. Warning: using require in place of include can lead to unwanted dependency cycles. - For instance the following manifest, with 'require' instead of 'include' - would produce a nasty dependence cycle, because notify imposes a before - between File[/foo] and Service[foo]:: + +For instance the following manifest, with 'require' instead of 'include' would produce a nasty dependence cycle, because notify imposes a before between File[/foo] and Service[foo]: class myservice { service { foo: ensure => running } diff --git a/lib/puppet/parser/functions/split.rb b/lib/puppet/parser/functions/split.rb index 5d0a9dabc..52394095a 100644 --- a/lib/puppet/parser/functions/split.rb +++ b/lib/puppet/parser/functions/split.rb @@ -6,7 +6,7 @@ module Puppet::Parser::Functions :doc => "\ Split a string variable into an array using the specified split regexp. - Usage:: + Usage: $string = 'v1.v2:v3.v4' $array_var1 = split($string, ':') diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb index 5ada0fed7..5eb4a4f9d 100644 --- a/lib/puppet/parser/functions/sprintf.rb +++ b/lib/puppet/parser/functions/sprintf.rb @@ -5,7 +5,7 @@ module Puppet::Parser::Functions :doc => "Perform printf-style formatting of text. - The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the ``Kernel::sprintf`` function in Ruby for all the details.") do |args| + The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the `Kernel::sprintf` function in Ruby for all the details.") do |args| raise Puppet::ParseError, 'sprintf() needs at least one argument' if args.length < 1 fmt = args.shift return sprintf(fmt, *args) diff --git a/lib/puppet/parser/functions/template.rb b/lib/puppet/parser/functions/template.rb index f51bcc1e2..6fa110332 100644 --- a/lib/puppet/parser/functions/template.rb +++ b/lib/puppet/parser/functions/template.rb @@ -1,6 +1,8 @@ Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :doc => - "Evaluate a template and return its value. See `the templating docs - <http://docs.puppetlabs.com/guides/templating.html>`_ for more information. + "Evaluate a template and return its value. See + [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for + more information. + Note that if multiple templates are specified, their output is all concatenated and returned as the output of the function.") do |vals| require 'erb' diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index b38406532..6091e0923 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -3,26 +3,26 @@ require 'puppet/util/package' Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, - + :doc => "Compares two versions -Prototype:: +Prototype: - \$result = versioncmp(a, b) + \$result = versioncmp(a, b) - where a and b are arbitrary version strings +Where a and b are arbitrary version strings -This functions returns a number:: +This functions returns a number: - * > 0 if version a is greater than version b - * == 0 if both version are equals - * < 0 if version a is less than version b +* Greater than 0 if version a is greater than version b +* Equal to 0 if both version are equals +* Less than 0 if version a is less than version b -Example:: +Example: - if versioncmp('2.6-1', '2.4.5') > 0 { - notice('2.6-1 is > than 2.4.5') - } + if versioncmp('2.6-1', '2.4.5') > 0 { + notice('2.6-1 is > than 2.4.5') + } ") do |args| diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index 7a316d4d7..ecb27f363 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -28,41 +28,33 @@ prechigh preclow rule -program: statements { - if val[0] - # Make sure we always return an array. - if val[0].is_a?(AST::ASTArray) - if val[0].children.empty? - result = nil - else - result = val[0] - end - else - result = aryfy(val[0]) - end - else - result = nil - end -} +program: statements_and_declarations | nil -statements: statement - | statements statement { - if val[0] and val[1] - if val[0].instance_of?(AST::ASTArray) + statements_and_declarations: statement_or_declaration { + result = ast AST::ASTArray, :children => (val[0] ? [val[0]] : []) + } + | statements_and_declarations statement_or_declaration { + if val[1] val[0].push(val[1]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[1]] end - elsif obj = (val[0] || val[1]) - result = obj - else result = nil + result = val[0] + } + +# statements is like statements_and_declarations, but it doesn't allow +# nested definitions, classes, or nodes. +statements: statements_and_declarations { + val[0].each do |stmt| + if stmt.is_a?(AST::TopLevelConstruct) + error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \ + :line => stmt.context[:line], :file => stmt.context[:file] + end end + result = val[0] } # The main list of valid statements -statement: resource +statement_or_declaration: resource | virtualresource | collection | assignment @@ -89,19 +81,17 @@ relationship_side: resource | resourceref | collection edge: IN_EDGE | OUT_EDGE | IN_EDGE_SUB | OUT_EDGE_SUB fstatement: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement } | NAME LPAREN funcvalues COMMA RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement } | NAME LPAREN RPAREN { result = ast AST::Function, @@ -111,29 +101,22 @@ fstatement: NAME LPAREN funcvalues RPAREN { :ftype => :statement } | NAME funcvalues { - args = aryfy(val[1]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[1], :ftype => :statement } -funcvalues: namestring - | resourceref +funcvalues: namestring { result = aryfy(val[0]) } + | resourceref { result = aryfy(val[0]) } | funcvalues COMMA namestring { - result = aryfy(val[0], val[2]) - result.line = @lexer.line - result.file = @lexer.file + val[0].push(val[2]) + result = val[0] } | funcvalues COMMA resourceref { - unless val[0].is_a?(AST::ASTArray) - val[0] = aryfy(val[0]) - end - - val[0].push(val[2]) - - result = val[0] + val[0].push(val[2]) + result = val[0] } # This is *almost* an rvalue, but I couldn't get a full @@ -152,23 +135,7 @@ namestring: name resource: classname LBRACE resourceinstances endsemi RBRACE { @lexer.commentpop - array = val[2] - array = [array] if array.instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray - - # this iterates across each specified resourceinstance - array.each { |instance| - raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance) - # now, i need to somehow differentiate between those things with - # arrays in their names, and normal things - - result.push ast( - AST::Resource, - :type => val[0], - :title => instance[0], - - :parameters => instance[1]) - } + result = ast(AST::Resource, :type => val[0], :instances => val[2]) } | classname LBRACE params endcomma RBRACE { # This is a deprecated syntax. error "All resource specifications require names" @@ -197,14 +164,8 @@ virtualresource: at resource { method = type.to_s + "=" - # Just mark our resources as exported and pass them through. - if val[1].instance_of?(AST::ASTArray) - val[1].each do |obj| - obj.send(method, true) - end - else - val[1].send(method, true) - end + # Just mark our resource as exported and pass it through. + val[1].send(method, true) result = val[1] } @@ -303,17 +264,13 @@ colllval: variable | name resourceinst: resourcename COLON params endcomma { - result = ast AST::ResourceInstance, :children => [val[0],val[2]] + result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] } -resourceinstances: resourceinst +resourceinstances: resourceinst { result = aryfy(val[0]) } | resourceinstances SEMIC resourceinst { - if val[0].instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray, :children => [val[0],val[2]] - else val[0].push val[2] result = val[0] - end } endsemi: # nothing @@ -358,14 +315,10 @@ params: # nothing { result = ast AST::ASTArray } - | param { result = val[0] } + | param { result = aryfy(val[0]) } | params COMMA param { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } param: NAME FARROW rvalue { @@ -384,24 +337,14 @@ anyparams: # nothing { result = ast AST::ASTArray } - | anyparam { result = val[0] } + | anyparam { result = aryfy(val[0]) } | anyparams COMMA anyparam { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } -rvalues: rvalue - | rvalues comma rvalue { - if val[0].instance_of?(AST::ASTArray) - result = val[0].push(val[2]) - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end -} +rvalues: rvalue { result = aryfy(val[0]) } + | rvalues comma rvalue { result = val[0].push(val[2]) } simplervalue: quotedtext | name @@ -425,10 +368,9 @@ rvalue: quotedtext # We currently require arguments in these functions. funcrvalue: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :rvalue } | NAME LPAREN RPAREN { result = ast AST::Function, @@ -572,19 +514,13 @@ expression: rvalue casestatement: CASE rvalue LBRACE caseopts RBRACE { @lexer.commentpop - options = val[3] - options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray) - result = ast AST::CaseStatement, :test => val[1], :options => options + result = ast AST::CaseStatement, :test => val[1], :options => val[3] } -caseopts: caseopt +caseopts: caseopt { result = aryfy(val[0]) } | caseopts caseopt { - if val[0].instance_of?(AST::ASTArray) val[0].push val[1] result = val[0] - else - result = ast AST::ASTArray, :children => [val[0], val[1]] - end } caseopt: casevalues COLON LBRACE statements RBRACE { @@ -601,14 +537,10 @@ caseopt: casevalues COLON LBRACE statements RBRACE { ) } -casevalues: selectlhand +casevalues: selectlhand { result = aryfy(val[0]) } | casevalues COMMA selectlhand { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } selector: selectlhand QMARK svalues { @@ -657,48 +589,51 @@ import: IMPORT strings { import(file) end - result = AST::ASTArray.new(:children => []) + result = nil } # Disable definition inheritance for now. 8/27/06, luke #definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE { definition: DEFINE classname argumentlist LBRACE statements RBRACE { @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line] + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :code => val[4], + :line => val[0][:line])) @lexer.indefine = false - result = nil #} | DEFINE NAME argumentlist parent LBRACE RBRACE { } | DEFINE classname argumentlist LBRACE RBRACE { @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line] + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) @lexer.indefine = false - result = nil } #hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE { -hostclass: CLASS classname argumentlist classparent LBRACE statements RBRACE { +hostclass: CLASS classname argumentlist classparent LBRACE statements_and_declarations RBRACE { @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :code => val[5], :line => val[0][:line])) } | CLASS classname argumentlist classparent LBRACE RBRACE { @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :line => val[0][:line])) } nodedef: NODE hostnames nodeparent LBRACE statements RBRACE { @lexer.commentpop - newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Node.new(val[1], + ast_context(true).merge(:parent => val[2], :code => val[4], + :line => val[0][:line])) } | NODE hostnames nodeparent LBRACE RBRACE { @lexer.commentpop - newnode val[1], :parent => val[2], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) } classref: CLASSREF { result = val[0][:value] } @@ -709,10 +644,11 @@ classname: NAME { result = val[0][:value] } # Multiple hostnames, as used for node names. These are all literal # strings, not AST objects. -hostnames: nodename +hostnames: nodename { + result = [result] +} | hostnames COMMA nodename { result = val[0] - result = [result] unless result.is_a?(Array) result << val[2] } @@ -778,22 +714,9 @@ variable: VARIABLE { result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] } -array: LBRACK rvalues RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end -} - | LBRACK rvalues COMMA RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end -} | LBRACK RBRACK { - result = ast AST::ASTArray -} +array: LBRACK rvalues RBRACK { result = val[1] } + | LBRACK rvalues COMMA RBRACK { result = val[1] } + | LBRACK RBRACK { result = ast AST::ASTArray } comma: FARROW | COMMA diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb index 1e10ff96c..31d39ae2f 100644 --- a/lib/puppet/parser/lexer.rb +++ b/lib/puppet/parser/lexer.rb @@ -221,7 +221,7 @@ class Puppet::Parser::Lexer TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true TOKENS.add_token :SQUOTE, "'" do |lexer, value| - [TOKENS[:STRING], lexer.slurpstring(value).first ] + [TOKENS[:STRING], lexer.slurpstring(value,["'"],:ignore_invalid_escapes).first ] end DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING} @@ -483,7 +483,7 @@ class Puppet::Parser::Lexer yield [final_token.name, token_value] if @previous_token - namestack(value) if @previous_token.name == :CLASS + namestack(value) if @previous_token.name == :CLASS and value != '{' if @previous_token.name == :DEFINE if indefine? @@ -517,24 +517,24 @@ class Puppet::Parser::Lexer # we've encountered the start of a string... # slurp in the rest of the string and return it - Valid_escapes_in_strings = %w{ \\ $ ' " n t s }+["\n"] - def slurpstring(terminators) + def slurpstring(terminators,escapes=%w{ \\ $ ' " n t s }+["\n"],ignore_invalid_escapes=false) # we search for the next quote that isn't preceded by a # backslash; the caret is there to match empty strings - str = @scanner.scan_until(/([^\\]|^)[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'" + str = @scanner.scan_until(/([^\\]|^|[^\\])([\\]{2})*[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'" @line += str.count("\n") # literal carriage returns add to the line count. - str.gsub!(/\\(.)/) { - case ch=$1 - when 'n'; "\n" - when 't'; "\t" - when 's'; " " - else - if Valid_escapes_in_strings.include? ch and not (ch == '"' and terminators == "'") - ch - else - Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" - "\\#{ch}" + str.gsub!(/\\(.)/m) { + ch = $1 + if escapes.include? ch + case ch + when 'n'; "\n" + when 't'; "\t" + when 's'; " " + when "\n": '' + else ch end + else + Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" unless ignore_invalid_escapes + "\\#{ch}" end } [ str[0..-2],str[-1,1] ] diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb index 5be9e5a3f..60b272e76 100644 --- a/lib/puppet/parser/parser.rb +++ b/lib/puppet/parser/parser.rb @@ -13,9 +13,9 @@ require 'puppet/parser/lexer' require 'puppet/parser/ast' module Puppet - class ParseError < Puppet::Error; end - class ImportError < Racc::ParseError; end - class AlreadyImportedError < ImportError; end + class ParseError < Puppet::Error; end + class ImportError < Racc::ParseError; end + class AlreadyImportedError < ImportError; end end @@ -25,7 +25,7 @@ module Puppet class Parser < Racc::Parser -module_eval <<'..end grammar.ra modeval..id7145220b1b', 'grammar.ra', 876 +module_eval <<'..end grammar.ra modeval..id6362f948d9', 'grammar.ra', 788 # It got too annoying having code in a file that needs to be compiled. require 'puppet/parser/parser_support' @@ -37,16 +37,17 @@ require 'puppet/parser/parser_support' # $Id$ -..end grammar.ra modeval..id7145220b1b +..end grammar.ra modeval..id6362f948d9 ##### racc 1.4.5 generates ### racc_reduce_table = [ 0, 0, :racc_error, - 1, 70, :_reduce_1, 1, 70, :_reduce_none, - 1, 71, :_reduce_none, + 1, 70, :_reduce_none, + 1, 71, :_reduce_3, 2, 71, :_reduce_4, + 1, 74, :_reduce_5, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, @@ -61,864 +62,820 @@ racc_reduce_table = [ 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, - 3, 87, :_reduce_19, - 3, 87, :_reduce_20, - 1, 88, :_reduce_none, - 1, 88, :_reduce_none, - 1, 88, :_reduce_none, - 1, 89, :_reduce_none, + 3, 88, :_reduce_20, + 3, 88, :_reduce_21, 1, 89, :_reduce_none, 1, 89, :_reduce_none, 1, 89, :_reduce_none, - 4, 81, :_reduce_28, - 5, 81, :_reduce_29, - 3, 81, :_reduce_30, - 2, 81, :_reduce_31, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 3, 91, :_reduce_34, - 3, 91, :_reduce_35, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_44, - 5, 74, :_reduce_45, - 5, 74, :_reduce_46, - 5, 74, :_reduce_47, - 5, 85, :_reduce_48, - 2, 75, :_reduce_49, - 1, 108, :_reduce_50, - 2, 108, :_reduce_51, - 6, 76, :_reduce_52, - 2, 76, :_reduce_53, - 3, 109, :_reduce_54, - 3, 109, :_reduce_55, - 1, 110, :_reduce_none, - 1, 110, :_reduce_none, - 3, 110, :_reduce_58, + 1, 90, :_reduce_none, + 1, 90, :_reduce_none, + 1, 90, :_reduce_none, + 1, 90, :_reduce_none, + 4, 82, :_reduce_29, + 5, 82, :_reduce_30, + 3, 82, :_reduce_31, + 2, 82, :_reduce_32, + 1, 92, :_reduce_33, + 1, 92, :_reduce_34, + 3, 92, :_reduce_35, + 3, 92, :_reduce_36, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_45, + 5, 75, :_reduce_46, + 5, 75, :_reduce_47, + 5, 75, :_reduce_48, + 5, 86, :_reduce_49, + 2, 76, :_reduce_50, + 1, 109, :_reduce_51, + 2, 109, :_reduce_52, + 6, 77, :_reduce_53, + 2, 77, :_reduce_54, + 3, 110, :_reduce_55, + 3, 110, :_reduce_56, 1, 111, :_reduce_none, - 3, 111, :_reduce_60, - 1, 112, :_reduce_61, - 1, 112, :_reduce_62, - 3, 113, :_reduce_63, - 3, 113, :_reduce_64, - 1, 114, :_reduce_none, - 1, 114, :_reduce_none, - 4, 116, :_reduce_67, - 1, 102, :_reduce_none, - 3, 102, :_reduce_69, - 0, 103, :_reduce_none, - 1, 103, :_reduce_none, - 1, 118, :_reduce_72, - 1, 93, :_reduce_73, - 1, 95, :_reduce_74, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 3, 77, :_reduce_82, - 3, 77, :_reduce_83, - 3, 86, :_reduce_84, - 0, 104, :_reduce_85, - 1, 104, :_reduce_86, - 3, 104, :_reduce_87, - 3, 122, :_reduce_88, - 3, 124, :_reduce_89, - 1, 125, :_reduce_none, - 1, 125, :_reduce_none, - 0, 107, :_reduce_92, - 1, 107, :_reduce_93, - 3, 107, :_reduce_94, - 1, 126, :_reduce_none, - 3, 126, :_reduce_96, - 1, 115, :_reduce_none, - 1, 115, :_reduce_none, - 1, 115, :_reduce_none, - 1, 115, :_reduce_none, + 1, 111, :_reduce_none, + 3, 111, :_reduce_59, + 1, 112, :_reduce_none, + 3, 112, :_reduce_61, + 1, 113, :_reduce_62, + 1, 113, :_reduce_63, + 3, 114, :_reduce_64, + 3, 114, :_reduce_65, 1, 115, :_reduce_none, 1, 115, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 4, 97, :_reduce_115, - 3, 97, :_reduce_116, - 1, 99, :_reduce_117, - 2, 99, :_reduce_118, - 2, 129, :_reduce_119, - 1, 130, :_reduce_120, - 2, 130, :_reduce_121, - 1, 96, :_reduce_122, - 4, 90, :_reduce_123, - 4, 90, :_reduce_124, - 2, 79, :_reduce_125, - 5, 131, :_reduce_126, - 4, 131, :_reduce_127, - 0, 132, :_reduce_none, - 2, 132, :_reduce_129, - 4, 132, :_reduce_130, - 3, 132, :_reduce_131, - 1, 120, :_reduce_none, - 3, 120, :_reduce_133, - 3, 120, :_reduce_134, - 3, 120, :_reduce_135, - 3, 120, :_reduce_136, - 3, 120, :_reduce_137, - 3, 120, :_reduce_138, - 3, 120, :_reduce_139, - 3, 120, :_reduce_140, - 3, 120, :_reduce_141, - 2, 120, :_reduce_142, - 3, 120, :_reduce_143, - 3, 120, :_reduce_144, - 3, 120, :_reduce_145, - 3, 120, :_reduce_146, - 3, 120, :_reduce_147, - 3, 120, :_reduce_148, - 2, 120, :_reduce_149, - 3, 120, :_reduce_150, - 3, 120, :_reduce_151, - 3, 120, :_reduce_152, - 5, 78, :_reduce_153, - 1, 134, :_reduce_none, - 2, 134, :_reduce_155, - 5, 135, :_reduce_156, - 4, 135, :_reduce_157, - 1, 136, :_reduce_none, - 3, 136, :_reduce_159, - 3, 98, :_reduce_160, + 4, 117, :_reduce_68, + 1, 103, :_reduce_69, + 3, 103, :_reduce_70, + 0, 104, :_reduce_none, + 1, 104, :_reduce_none, + 1, 119, :_reduce_73, + 1, 94, :_reduce_74, + 1, 96, :_reduce_75, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 3, 78, :_reduce_83, + 3, 78, :_reduce_84, + 3, 87, :_reduce_85, + 0, 105, :_reduce_86, + 1, 105, :_reduce_87, + 3, 105, :_reduce_88, + 3, 123, :_reduce_89, + 3, 125, :_reduce_90, + 1, 126, :_reduce_none, + 1, 126, :_reduce_none, + 0, 108, :_reduce_93, + 1, 108, :_reduce_94, + 3, 108, :_reduce_95, + 1, 127, :_reduce_96, + 3, 127, :_reduce_97, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 4, 98, :_reduce_116, + 3, 98, :_reduce_117, + 1, 100, :_reduce_118, + 2, 100, :_reduce_119, + 2, 130, :_reduce_120, + 1, 131, :_reduce_121, + 2, 131, :_reduce_122, + 1, 97, :_reduce_123, + 4, 91, :_reduce_124, + 4, 91, :_reduce_125, + 2, 80, :_reduce_126, + 5, 132, :_reduce_127, + 4, 132, :_reduce_128, + 0, 133, :_reduce_none, + 2, 133, :_reduce_130, + 4, 133, :_reduce_131, + 3, 133, :_reduce_132, + 1, 121, :_reduce_none, + 3, 121, :_reduce_134, + 3, 121, :_reduce_135, + 3, 121, :_reduce_136, + 3, 121, :_reduce_137, + 3, 121, :_reduce_138, + 3, 121, :_reduce_139, + 3, 121, :_reduce_140, + 3, 121, :_reduce_141, + 3, 121, :_reduce_142, + 2, 121, :_reduce_143, + 3, 121, :_reduce_144, + 3, 121, :_reduce_145, + 3, 121, :_reduce_146, + 3, 121, :_reduce_147, + 3, 121, :_reduce_148, + 3, 121, :_reduce_149, + 2, 121, :_reduce_150, + 3, 121, :_reduce_151, + 3, 121, :_reduce_152, + 3, 121, :_reduce_153, + 5, 79, :_reduce_154, + 1, 135, :_reduce_155, + 2, 135, :_reduce_156, + 5, 136, :_reduce_157, + 4, 136, :_reduce_158, + 1, 137, :_reduce_159, + 3, 137, :_reduce_160, + 3, 99, :_reduce_161, + 1, 139, :_reduce_none, + 4, 139, :_reduce_163, + 1, 141, :_reduce_none, + 3, 141, :_reduce_165, + 3, 140, :_reduce_166, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, 1, 138, :_reduce_none, - 4, 138, :_reduce_162, - 1, 140, :_reduce_none, - 3, 140, :_reduce_164, - 3, 139, :_reduce_165, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_173, - 1, 137, :_reduce_none, - 1, 141, :_reduce_175, - 1, 142, :_reduce_none, - 3, 142, :_reduce_177, - 2, 80, :_reduce_178, - 6, 82, :_reduce_179, - 5, 82, :_reduce_180, - 7, 83, :_reduce_181, - 6, 83, :_reduce_182, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, + 1, 138, :_reduce_174, + 1, 138, :_reduce_none, + 1, 142, :_reduce_176, + 1, 143, :_reduce_none, + 3, 143, :_reduce_178, + 2, 81, :_reduce_179, + 6, 83, :_reduce_180, + 5, 83, :_reduce_181, + 7, 84, :_reduce_182, 6, 84, :_reduce_183, - 5, 84, :_reduce_184, - 1, 106, :_reduce_185, - 1, 101, :_reduce_186, - 1, 101, :_reduce_187, - 1, 101, :_reduce_188, - 1, 145, :_reduce_none, - 3, 145, :_reduce_190, - 1, 147, :_reduce_191, + 6, 85, :_reduce_184, + 5, 85, :_reduce_185, + 1, 107, :_reduce_186, + 1, 102, :_reduce_187, + 1, 102, :_reduce_188, + 1, 102, :_reduce_189, + 1, 146, :_reduce_190, + 3, 146, :_reduce_191, 1, 148, :_reduce_192, - 1, 148, :_reduce_193, - 1, 148, :_reduce_194, - 1, 148, :_reduce_none, - 0, 72, :_reduce_196, - 0, 149, :_reduce_197, - 1, 143, :_reduce_none, - 3, 143, :_reduce_199, - 3, 143, :_reduce_200, - 1, 150, :_reduce_none, - 3, 150, :_reduce_202, - 3, 151, :_reduce_203, - 1, 151, :_reduce_204, - 3, 151, :_reduce_205, - 1, 151, :_reduce_206, - 1, 146, :_reduce_none, - 2, 146, :_reduce_208, + 1, 149, :_reduce_193, + 1, 149, :_reduce_194, + 1, 149, :_reduce_195, + 1, 149, :_reduce_none, + 0, 72, :_reduce_197, + 0, 150, :_reduce_198, 1, 144, :_reduce_none, - 2, 144, :_reduce_210, - 1, 152, :_reduce_none, - 1, 152, :_reduce_none, - 1, 94, :_reduce_213, - 3, 119, :_reduce_214, - 4, 119, :_reduce_215, - 2, 119, :_reduce_216, - 1, 127, :_reduce_none, - 1, 127, :_reduce_none, - 0, 105, :_reduce_none, - 1, 105, :_reduce_220, - 1, 133, :_reduce_221, - 3, 128, :_reduce_222, - 4, 128, :_reduce_223, - 2, 128, :_reduce_224, + 3, 144, :_reduce_200, + 3, 144, :_reduce_201, + 1, 151, :_reduce_none, + 3, 151, :_reduce_203, + 3, 152, :_reduce_204, + 1, 152, :_reduce_205, + 3, 152, :_reduce_206, + 1, 152, :_reduce_207, + 1, 147, :_reduce_none, + 2, 147, :_reduce_209, + 1, 145, :_reduce_none, + 2, 145, :_reduce_211, 1, 153, :_reduce_none, - 3, 153, :_reduce_226, + 1, 153, :_reduce_none, + 1, 95, :_reduce_214, + 3, 120, :_reduce_215, + 4, 120, :_reduce_216, + 2, 120, :_reduce_217, + 1, 128, :_reduce_none, + 1, 128, :_reduce_none, + 0, 106, :_reduce_none, + 1, 106, :_reduce_221, + 1, 134, :_reduce_222, + 3, 129, :_reduce_223, + 4, 129, :_reduce_224, + 2, 129, :_reduce_225, + 1, 154, :_reduce_none, 3, 154, :_reduce_227, - 1, 155, :_reduce_228, - 1, 155, :_reduce_229, - 4, 121, :_reduce_230, - 1, 100, :_reduce_none, - 4, 100, :_reduce_232 ] + 3, 155, :_reduce_228, + 1, 156, :_reduce_229, + 1, 156, :_reduce_230, + 4, 122, :_reduce_231, + 1, 101, :_reduce_none, + 4, 101, :_reduce_233 ] -racc_reduce_n = 233 +racc_reduce_n = 234 -racc_shift_n = 384 +racc_shift_n = 385 racc_action_table = [ - 256, 257, 228, 82, 54, 72, 75, 181, 251, 48, - 72, 75, 194, 205, 210, 163, 156, 348, 46, 47, - 344, 184, 201, 203, 206, 209, 162, 352, 54, 182, - 351, 169, 54, -168, 72, 75, 241, 242, 102, 305, - 106, 158, 58, 193, 230, 60, 204, 208, 193, 306, - 213, 196, 197, 198, 200, 202, 97, 207, 211, 72, - 75, 72, 75, 163, 199, 59, 58, 71, 245, 60, - 58, 83, 86, 60, 162, 92, 244, 72, 75, 169, - 78, 100, 352, 269, 89, 351, 63, 94, 64, 59, - 228, 326, 71, 59, 162, 59, 83, 86, 83, 268, - 92, 65, 92, 184, 76, 78, 307, 137, 163, 89, - 162, 89, 72, 75, 83, 268, 241, 242, 92, 162, - 59, 163, 59, 137, 169, 62, 254, 89, 207, 211, - 72, 75, 162, 308, 102, 199, 106, 169, 59, 255, - 213, 196, 197, 198, -166, 162, 309, 207, 211, 83, - 268, 310, 97, 92, 199, 72, 75, 355, 137, 102, - -170, 106, 89, 71, 218, 356, 173, 83, 86, 220, - 313, 92, -171, 59, 72, 75, 78, 100, 37, 218, - 89, 249, 38, 94, 220, 246, 247, 173, 71, 11, - 210, 59, 83, 86, 246, 367, 92, 271, 201, 37, - -167, 78, 37, 38, 270, 89, 38, 71, 246, 247, - 11, 83, 86, 11, 14, 92, 59, 72, 75, 76, - 78, 102, 278, 106, 89, 277, 213, 196, 197, 198, - 200, 202, 275, 207, 211, 59, 246, 274, 152, 97, - 199, 37, 318, 72, 75, 127, 319, 102, -169, 106, - 71, 63, 11, 14, 83, 86, -167, 37, 92, 207, - 211, 127, -169, 78, 100, 97, 199, 89, 11, 14, - 94, -166, 117, 72, 75, -185, 71, 82, 59, 336, - 83, 86, 197, 198, 92, 231, 338, 207, 211, 78, - 100, 181, 48, 89, 199, 74, 94, 240, -168, 72, - 75, 241, 242, 102, 59, 106, 71, 184, 176, 37, - 83, 86, 59, 38, 92, 345, 322, 175, 76, 78, - 11, 97, -172, 89, -171, 72, 75, -170, 59, 102, - 214, 106, 71, 64, 59, 215, 83, 86, 173, 217, - 92, -23, -23, -23, -23, 78, 100, 97, 155, 89, - 72, 75, 94, 122, 102, 152, 106, 82, 71, 223, - 59, 122, 83, 86, 72, 75, 92, -168, 102, 225, - 106, 78, 100, -166, 276, 89, 226, 117, 94, 44, - 45, 41, 42, 71, -169, -167, 59, 83, 86, 72, - 75, 92, 226, 102, 229, 106, 78, 71, 52, -168, - 89, 83, 86, 72, 75, 92, -166, 102, -169, 106, - 78, 59, 197, 198, 89, -167, -171, 207, 211, 365, - 231, 152, 71, 234, 199, 59, 83, 86, 50, 210, - 92, -21, -21, -21, -21, 78, 71, 201, 372, 89, - 83, 86, 49, 374, 92, 72, 75, 228, -220, 78, - 59, 226, 354, 89, 377, 72, 75, 40, 39, 102, - 237, 106, 341, nil, 59, 213, 196, 197, 198, 200, - 202, nil, 207, 211, nil, nil, nil, 97, 162, 199, - nil, nil, 83, 268, nil, nil, 92, nil, 71, nil, - nil, 137, 83, 86, nil, 89, 92, 44, 45, 41, - 42, 78, 100, 72, 75, 89, 59, 102, 94, 106, - 213, 196, 197, 198, 200, 202, 59, 207, 211, nil, - 213, 196, 197, 198, 199, 97, nil, 207, 211, 72, - 75, nil, nil, 102, 199, 106, 71, nil, nil, nil, - 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, - 100, 97, nil, 89, nil, nil, 94, nil, nil, 72, - 75, nil, 71, 102, 59, 106, 83, 86, nil, nil, - 92, nil, nil, nil, nil, 78, 100, nil, nil, 89, - nil, 97, 94, nil, nil, 72, 75, nil, nil, 102, - 59, 106, 71, nil, nil, nil, 83, 86, nil, nil, - 92, nil, nil, nil, nil, 78, 100, 97, nil, 89, - 72, 75, 94, nil, 102, nil, 106, nil, 71, nil, - 59, nil, 83, 86, 72, 75, 92, nil, 102, nil, - nil, 78, 100, nil, nil, 89, nil, nil, 94, nil, - nil, nil, nil, 71, nil, nil, 59, 83, 86, 72, - 75, 92, nil, 102, nil, 106, 78, 71, nil, nil, - 89, 83, 143, nil, nil, 92, nil, nil, nil, nil, - 137, 59, nil, nil, 89, 72, 75, nil, nil, 102, - nil, 106, 71, nil, nil, 59, 83, 86, nil, nil, - 92, nil, nil, nil, nil, 78, nil, 97, nil, 89, - nil, 72, 75, nil, nil, 102, nil, 106, 71, nil, - 59, nil, 83, 86, nil, nil, 92, nil, nil, nil, - nil, 78, 100, 97, nil, 89, nil, nil, 94, nil, - nil, 72, 75, nil, 71, 102, 59, 106, 83, 86, - nil, nil, 92, nil, nil, nil, nil, 78, 100, nil, - nil, 89, nil, 97, 94, nil, nil, 72, 75, nil, - nil, 102, 59, 106, 71, nil, nil, nil, 83, 86, - nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, - nil, 89, 72, 75, 94, nil, 102, nil, 106, nil, - 71, nil, 59, nil, 83, 86, nil, nil, 92, nil, - nil, nil, nil, 78, 100, nil, nil, 89, 72, 75, - 94, nil, 102, nil, 106, 71, nil, nil, 59, 83, - 86, nil, nil, 92, nil, nil, nil, nil, 78, nil, - 97, nil, 89, nil, 72, 75, nil, nil, 102, nil, - 106, 71, nil, 59, nil, 83, 86, nil, nil, 92, - nil, nil, 72, 75, 78, 100, 97, nil, 89, 72, - 75, 94, nil, 102, nil, 106, nil, 71, nil, 59, - nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, - 78, 100, nil, nil, 89, 162, nil, 94, nil, 83, - 268, nil, 71, 92, nil, 59, 83, 86, 137, nil, - 92, nil, 89, nil, nil, 78, 72, 75, nil, 89, - 102, nil, 106, 59, nil, nil, nil, nil, nil, nil, - 59, nil, nil, nil, nil, 72, 75, nil, 97, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 71, - nil, nil, nil, 83, 86, nil, nil, 92, 177, nil, - 72, 75, 78, 100, nil, nil, 89, nil, 71, 94, - nil, nil, 83, 86, nil, nil, 92, 59, 72, 75, - 76, 78, 102, 339, 106, 89, nil, nil, nil, nil, - nil, nil, nil, 71, nil, nil, 59, 83, 86, nil, - 97, 92, nil, 72, 75, 76, 78, 102, nil, 106, - 89, 71, nil, 72, 75, 83, 86, nil, nil, 92, - nil, 59, nil, nil, 78, 100, nil, nil, 89, 72, - 75, 94, nil, nil, nil, nil, 71, nil, nil, 59, - 83, 86, nil, nil, 92, nil, 162, nil, nil, 78, - 83, 268, nil, 89, 92, nil, 72, 75, nil, 137, - 102, nil, 162, 89, 59, nil, 83, 268, nil, nil, - 92, nil, 72, 75, 59, 137, 102, nil, 106, 89, - nil, nil, 72, 75, nil, nil, 102, nil, 106, 71, - 59, nil, nil, 83, 268, nil, nil, 92, nil, nil, - nil, nil, 137, nil, 97, 71, 89, nil, nil, 83, - 86, nil, nil, 92, nil, 71, nil, 59, 78, 83, - 86, nil, 89, 92, nil, nil, nil, nil, 78, 100, - 72, 75, 89, 59, 102, 94, 106, 213, 196, 197, - 198, 200, 202, 59, 207, 211, nil, nil, nil, 72, - 75, 199, 97, 102, 189, 106, 72, 75, nil, nil, - 102, nil, 106, 71, nil, nil, nil, 83, 86, nil, - nil, 92, nil, nil, nil, nil, 78, 100, 72, 75, - 89, nil, 71, 94, nil, nil, 83, 86, nil, 71, - 92, 59, nil, 83, 86, 78, nil, 92, nil, 89, - nil, nil, 78, 72, 75, nil, 89, 102, nil, 106, - 59, 162, nil, nil, nil, 83, 268, 59, nil, 92, - nil, 72, 75, nil, 137, 102, nil, 106, 89, nil, - nil, nil, nil, nil, nil, nil, 71, nil, nil, 59, - 83, 86, nil, 97, 92, nil, nil, nil, nil, 78, - nil, 72, 75, 89, 71, 102, nil, 106, 83, 86, - nil, nil, 92, nil, 59, nil, nil, 78, 100, nil, - nil, 89, nil, 97, 94, nil, nil, 72, 75, nil, - nil, 102, 59, 106, 71, nil, nil, nil, 83, 86, - nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, - nil, 89, nil, nil, 94, nil, nil, nil, nil, nil, - 71, nil, 59, nil, 83, 86, 212, nil, 92, nil, - nil, nil, nil, 78, 100, 205, 210, 89, nil, nil, - 94, nil, nil, nil, 201, 203, 206, 209, 59, nil, - 205, 210, nil, nil, nil, nil, nil, nil, nil, 201, - 203, 206, 209, nil, nil, nil, nil, nil, 204, 208, - nil, nil, 213, 196, 197, 198, 200, 202, nil, 207, - 211, nil, nil, 204, 208, nil, 199, 213, 196, 197, - 198, 200, 202, nil, 207, 211, 205, 210, nil, nil, - nil, 199, nil, nil, nil, 201, 203, 206, 209, nil, - nil, 205, 210, nil, nil, nil, nil, nil, nil, nil, - 201, 203, 206, 209, nil, nil, nil, nil, nil, 204, - 208, nil, nil, 213, 196, 197, 198, 200, 202, nil, - 207, 211, nil, nil, 204, 208, nil, 199, 213, 196, - 197, 198, 200, 202, nil, 207, 211, 205, 210, nil, - nil, nil, 199, nil, nil, nil, 201, 203, 206, 209, - nil, nil, 205, 210, nil, nil, nil, nil, nil, nil, - 273, 201, 203, 206, 209, nil, nil, nil, nil, nil, - nil, 208, nil, nil, 213, 196, 197, 198, 200, 202, - nil, 207, 211, nil, nil, 204, 208, nil, 199, 213, - 196, 197, 198, 200, 202, nil, 207, 211, 205, 210, - nil, nil, nil, 199, nil, nil, nil, 201, 203, 206, - 209, nil, nil, 26, 210, 33, 1, nil, 7, 12, - nil, 17, 201, 23, nil, 29, nil, 3, nil, nil, - 11, 14, nil, 210, nil, 213, 196, 197, 198, 200, - 202, 201, 207, 211, nil, nil, nil, nil, nil, 199, - 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, - nil, 324, nil, nil, 199, nil, nil, nil, nil, 213, - 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, - 379, nil, 26, 199, 33, 1, nil, 7, 12, nil, - 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, - 14, 26, 382, 33, 1, nil, 7, 12, nil, 17, - nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, - nil, 296, nil, 26, nil, 33, 1, nil, 7, 12, - nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, - 11, 14, 26, 364, 33, 1, nil, 7, 12, nil, - 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, - 14, nil, 381, nil, 26, nil, 33, 1, nil, 7, - 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, - nil, 11, 14, 26, 383, 33, 1, nil, 7, 12, - nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, - 11, 14, nil, 357, nil, 26, nil, 33, 1, nil, - 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, - nil, nil, 11, 14, 26, 363, 33, 1, nil, 7, - 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, - nil, 11, 14, nil, 375, nil, 26, nil, 33, 1, - nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, - 3, nil, nil, 11, 14, 26, 304, 33, 1, nil, - 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, - nil, nil, 11, 14, nil, 349, nil, 26, nil, 33, - 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, - nil, 3, nil, nil, 11, 14, 26, nil, 33, 1, - nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, - 3, nil, nil, 11, 14, 26, nil, 33, 1, nil, - 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, - nil, nil, 11, 14 ] + 242, 243, 55, 231, 356, 112, 157, 113, 78, 298, + 68, 71, 357, 181, 186, 326, 344, 340, 55, 295, + 114, 231, 177, 179, 182, 185, 170, 294, 68, 71, + 286, 158, 100, 285, 103, 68, 71, 291, 292, 55, + 59, 291, 292, 61, 111, 233, 180, 184, 198, 231, + 189, 172, 173, 174, 176, 178, 59, 183, 187, 61, + -168, 66, 170, 60, 175, 79, 81, 186, 202, 88, + 112, 166, 79, 252, 74, 177, 88, 59, 84, 60, + 61, 139, 68, 71, 333, 84, 100, 117, 103, 60, + 36, -170, 68, 71, 38, 306, 60, 307, 203, 240, + 60, 10, 203, 189, 172, 173, 174, 176, 178, 202, + 183, 187, 241, 202, 209, 66, 218, 175, 209, 79, + 81, 219, 284, 88, 309, 202, 256, 283, 74, 79, + 252, 308, 84, 88, 203, 68, 71, 310, 139, 100, + 203, 103, 84, 60, 218, 202, 256, 367, 36, 219, + 209, 202, 38, 60, 68, 71, 209, 95, 100, 10, + 103, 68, 71, 68, 71, 100, 337, 103, 66, 335, + 199, 154, 79, 81, 173, 174, 88, 183, 187, 183, + 187, 74, 99, 95, 175, 84, 175, 66, 90, 311, + 337, 79, 81, 335, 66, 88, 60, 287, 79, 81, + 74, 198, 88, 315, 84, 68, 71, 74, 99, -172, + 213, 84, 68, 71, 90, 60, 100, 36, 103, 68, + 71, 38, 60, 100, 318, 103, 68, 71, 10, 15, + 36, -167, 213, 355, 38, 167, 36, 313, 202, 154, + 127, 10, 79, 252, 323, 66, 88, 10, 15, 79, + 81, 139, 66, 88, 166, 84, 79, 81, 74, 202, + 88, 229, 84, 79, 252, 74, 60, 88, 49, 84, + 68, 71, 139, 60, 78, -186, 84, 47, 48, 49, + 60, 329, 36, 170, 183, 187, 127, 60, -169, 68, + 71, 175, 70, 10, 15, 68, 71, 161, -171, 100, + 289, 103, -169, 66, 291, 292, 60, 79, 81, 258, + -167, 88, -170, 256, 257, 72, 74, 95, -168, 60, + 84, 156, 66, 154, 68, 71, 79, 81, 66, 122, + 88, 60, 79, 81, 72, 74, 88, -170, -173, 84, + -172, 74, 99, 68, 71, 84, -171, 100, 90, 103, + 60, 200, 334, 68, 71, 213, 60, 202, 215, 254, + 338, 79, 252, 173, 174, 88, 122, 296, 183, 187, + 139, 256, 257, 216, 84, 175, 66, 234, 68, 71, + 79, 81, 113, 117, 88, 60, 202, 217, 78, 74, + 79, 252, 353, 84, 88, 53, 68, 71, 223, 139, + 100, 260, 103, 84, 60, 43, 44, 40, 41, 358, + 52, 66, 51, 225, 60, 79, 81, -169, 229, 88, + 365, 68, 71, 72, 74, 100, 238, 103, 84, 66, + 228, -167, 234, 79, 81, 372, 373, 88, -169, 60, + -167, -170, 74, 95, -168, -172, 84, 68, 71, 45, + 375, 100, 229, 103, 66, -221, 232, 60, 79, 81, + 378, 39, 88, -24, -24, -24, -24, 74, 99, 95, + -168, 84, 383, 384, 90, nil, nil, 68, 71, nil, + 66, 100, 60, 103, 79, 81, nil, nil, 88, -22, + -22, -22, -22, 74, 99, nil, nil, 84, nil, 95, + 90, nil, nil, 68, 71, nil, nil, 100, 60, 103, + 66, nil, nil, nil, 79, 81, nil, nil, 88, 43, + 44, 40, 41, 74, 99, 95, nil, 84, nil, nil, + 90, nil, nil, 68, 71, nil, 66, 100, 60, 103, + 79, 81, nil, nil, 88, nil, nil, nil, nil, 74, + 99, nil, nil, 84, nil, 95, 90, nil, nil, 68, + 71, nil, nil, 100, 60, 103, 66, nil, nil, nil, + 79, 81, nil, nil, 88, nil, nil, 68, 71, 74, + 99, 100, nil, 84, 68, 71, 90, nil, 100, nil, + 103, nil, 66, nil, 60, nil, 79, 81, nil, nil, + 88, nil, nil, nil, nil, 74, 95, nil, nil, 84, + 66, nil, nil, nil, 79, 144, nil, 66, 88, nil, + 60, 79, 81, 139, nil, 88, nil, 84, nil, nil, + 74, 99, nil, nil, 84, 68, 71, 90, 60, 100, + nil, 103, nil, nil, nil, 60, nil, nil, nil, nil, + nil, nil, nil, nil, 68, 71, nil, 95, 100, nil, + 103, 68, 71, nil, nil, 100, nil, 103, 66, nil, + nil, nil, 79, 81, nil, nil, 88, nil, nil, 68, + 71, 74, 99, nil, nil, 84, nil, 66, 90, nil, + nil, 79, 81, nil, 66, 88, 60, nil, 79, 81, + 74, nil, 88, nil, 84, 68, 71, 74, nil, nil, + nil, 84, 202, nil, nil, 60, 79, 252, nil, nil, + 88, nil, 60, nil, nil, 139, 68, 71, 162, 84, + 100, nil, 103, nil, nil, nil, nil, nil, 66, nil, + 60, nil, 79, 81, nil, nil, 88, nil, 95, nil, + 72, 74, 68, 71, nil, 84, 100, nil, 103, 66, + nil, nil, nil, 79, 81, nil, 60, 88, nil, nil, + nil, nil, 74, 99, 95, nil, 84, 68, 71, 90, + nil, nil, nil, nil, nil, 66, nil, 60, nil, 79, + 81, nil, nil, 88, nil, nil, nil, nil, 74, 99, + 327, nil, 84, 68, 71, 90, nil, 100, nil, 103, + 66, nil, nil, 60, 79, 81, nil, nil, 88, nil, + nil, nil, 72, 74, nil, 95, nil, 84, 68, 71, + nil, nil, 100, nil, 103, nil, 66, nil, 60, nil, + 79, 81, 68, 71, 88, nil, 100, nil, 103, 74, + 99, nil, nil, 84, nil, nil, 90, nil, nil, nil, + nil, 66, nil, nil, 60, 79, 81, 68, 71, 88, + nil, 100, nil, 103, 74, 66, nil, nil, 84, 79, + 81, 68, 71, 88, nil, 100, nil, nil, 74, 60, + nil, nil, 84, nil, nil, nil, nil, nil, nil, nil, + 66, nil, nil, 60, 79, 81, nil, nil, 88, nil, + nil, 68, 71, 74, 66, nil, nil, 84, 79, 252, + nil, nil, 88, nil, nil, nil, nil, 139, 60, 68, + 71, 84, nil, 100, nil, 103, nil, nil, nil, nil, + nil, nil, 60, nil, 202, nil, nil, nil, 79, 252, + nil, 95, 88, nil, nil, nil, nil, 139, nil, 68, + 71, 84, 66, 100, nil, 103, 79, 81, nil, nil, + 88, nil, 60, nil, nil, 74, 99, nil, nil, 84, + nil, 95, 90, nil, nil, 68, 71, nil, nil, 100, + 60, 103, 66, nil, nil, nil, 79, 81, nil, nil, + 88, nil, nil, nil, nil, 74, 99, 95, nil, 84, + nil, nil, 90, nil, nil, 68, 71, nil, 66, 100, + 60, 103, 79, 81, nil, nil, 88, nil, nil, nil, + nil, 74, 99, nil, nil, 84, nil, 95, 90, nil, + nil, 68, 71, nil, nil, 100, 60, 103, 66, nil, + nil, nil, 79, 81, nil, nil, 88, nil, nil, nil, + nil, 74, 99, 95, nil, 84, nil, nil, 90, nil, + nil, 68, 71, nil, 66, 100, 60, 103, 79, 81, + nil, nil, 88, nil, nil, nil, nil, 74, 99, nil, + nil, 84, nil, 95, 90, nil, nil, 68, 71, nil, + nil, 100, 60, 103, 66, nil, nil, nil, 79, 81, + nil, nil, 88, nil, nil, nil, nil, 74, 99, 95, + nil, 84, nil, nil, 90, nil, nil, 68, 71, nil, + 66, 100, 60, 103, 79, 81, nil, nil, 88, nil, + nil, nil, nil, 74, 99, nil, nil, 84, nil, 95, + 90, nil, nil, 68, 71, nil, nil, 100, 60, 103, + 66, nil, nil, nil, 79, 81, nil, nil, 88, nil, + nil, nil, nil, 74, 99, 95, nil, 84, 68, 71, + 90, nil, 100, 193, 103, nil, 66, nil, 60, nil, + 79, 81, nil, nil, 88, nil, nil, nil, nil, 74, + 99, nil, nil, 84, 68, 71, 90, nil, 100, nil, + 103, 66, nil, nil, 60, 79, 81, nil, nil, 88, + nil, nil, nil, nil, 74, nil, 95, nil, 84, nil, + 68, 71, nil, nil, 100, nil, 103, 66, nil, 60, + nil, 79, 81, nil, nil, 88, nil, nil, nil, nil, + 74, 99, 95, nil, 84, nil, nil, 90, nil, nil, + nil, nil, nil, 66, nil, 60, nil, 79, 81, 188, + nil, 88, nil, nil, nil, nil, 74, 99, 181, 186, + 84, nil, nil, 90, nil, nil, nil, 177, 179, 182, + 185, 60, nil, 181, 186, nil, nil, nil, nil, nil, + nil, 282, 177, 179, 182, 185, nil, nil, nil, nil, + nil, 180, 184, nil, nil, 189, 172, 173, 174, 176, + 178, nil, 183, 187, nil, nil, 180, 184, nil, 175, + 189, 172, 173, 174, 176, 178, nil, 183, 187, 181, + 186, nil, nil, nil, 175, nil, nil, nil, 177, 179, + 182, 185, nil, nil, 181, 186, nil, nil, nil, nil, + nil, nil, nil, 177, 179, 182, 185, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 189, 172, 173, 174, + 176, 178, nil, 183, 187, nil, nil, 180, 184, nil, + 175, 189, 172, 173, 174, 176, 178, nil, 183, 187, + 181, 186, nil, nil, nil, 175, nil, nil, nil, 177, + 179, 182, 185, nil, nil, 181, 186, nil, nil, nil, + nil, nil, nil, nil, 177, 179, 182, 185, nil, nil, + nil, nil, nil, 180, 184, nil, nil, 189, 172, 173, + 174, 176, 178, nil, 183, 187, nil, nil, nil, 184, + nil, 175, 189, 172, 173, 174, 176, 178, nil, 183, + 187, 181, 186, nil, nil, nil, 175, nil, nil, nil, + 177, 179, 182, 185, nil, nil, nil, 186, nil, 189, + 172, 173, 174, 176, 178, 177, 183, 187, nil, nil, + nil, nil, nil, 175, 180, 184, 186, nil, 189, 172, + 173, 174, 176, 178, 177, 183, 187, nil, nil, nil, + nil, 186, 175, 189, 172, 173, 174, 176, 178, 177, + 183, 187, nil, nil, nil, nil, nil, 175, nil, nil, + nil, nil, 189, 172, 173, 174, 176, 178, nil, 183, + 187, 280, nil, nil, nil, nil, 175, 189, 172, 173, + 174, 176, 178, nil, 183, 187, nil, nil, nil, nil, + 325, 175, 26, nil, 32, 1, nil, 8, 11, nil, + 18, nil, 23, nil, 29, nil, 2, nil, nil, 10, + 15, 26, 363, 32, 1, nil, 8, 11, nil, 18, + nil, 23, nil, 29, nil, 2, nil, nil, 10, 15, + nil, 382, nil, 26, nil, 32, 1, nil, 8, 11, + nil, 18, nil, 23, nil, 29, nil, 2, nil, nil, + 10, 15, 26, 380, 32, 1, nil, 8, 11, nil, + 18, nil, 23, nil, 29, nil, 2, nil, nil, 10, + 15, nil, 376, nil, 26, nil, 32, 1, nil, 8, + 11, nil, 18, nil, 23, nil, 29, nil, 2, nil, + nil, 10, 15, 26, 305, 32, 1, nil, 8, 11, + nil, 18, nil, 23, nil, 29, nil, 2, nil, nil, + 10, 15, nil, nil, nil, 26, nil, 32, 1, nil, + 8, 11, nil, 18, nil, 23, nil, 29, nil, 2, + nil, nil, 10, 15, 26, nil, 32, 1, nil, 8, + 11, nil, 18, nil, 23, nil, 29, nil, 2, nil, + nil, 10, 15, 26, nil, 32, 1, nil, 8, 11, + nil, 18, nil, 23, nil, 29, nil, 2, nil, nil, + 10, 15, 26, nil, 32, 1, nil, 8, 11, nil, + 18, nil, 23, nil, 29, nil, 2, nil, nil, 10, + 15, 189, 172, 173, 174, 176, 178, nil, 183, 187, + 189, 172, 173, 174, nil, 175, nil, 183, 187, 189, + 172, 173, 174, nil, 175, nil, 183, 187, nil, nil, + nil, nil, nil, 175 ] racc_action_check = [ - 180, 180, 152, 86, 156, 106, 106, 272, 174, 7, - 277, 277, 106, 180, 180, 65, 55, 277, 7, 7, - 272, 86, 180, 180, 180, 180, 65, 296, 17, 80, - 296, 65, 158, 95, 202, 202, 174, 174, 202, 218, - 202, 55, 156, 106, 152, 156, 180, 180, 277, 219, - 180, 180, 180, 180, 180, 180, 202, 180, 180, 181, - 181, 368, 368, 239, 180, 156, 17, 202, 165, 17, - 158, 202, 202, 158, 239, 202, 165, 182, 182, 239, - 202, 202, 349, 182, 202, 349, 22, 202, 22, 17, - 143, 243, 181, 158, 368, 202, 181, 181, 368, 368, - 181, 22, 368, 143, 181, 181, 220, 368, 163, 181, - 182, 368, 355, 355, 182, 182, 243, 243, 182, 163, - 181, 62, 368, 182, 163, 22, 178, 182, 281, 281, - 351, 351, 62, 221, 351, 281, 351, 62, 182, 178, - 285, 285, 285, 285, 101, 355, 221, 285, 285, 355, - 355, 224, 351, 355, 285, 341, 341, 300, 355, 341, - 91, 341, 355, 351, 308, 300, 226, 351, 351, 308, - 227, 351, 90, 355, 184, 184, 351, 351, 12, 122, - 351, 171, 12, 351, 122, 171, 171, 229, 341, 12, - 286, 351, 341, 341, 343, 343, 341, 184, 286, 1, - 87, 341, 30, 1, 183, 341, 30, 184, 183, 183, - 1, 184, 184, 30, 30, 184, 341, 196, 196, 184, - 184, 196, 195, 196, 184, 195, 286, 286, 286, 286, - 286, 286, 188, 286, 286, 184, 188, 188, 231, 196, - 286, 120, 232, 197, 197, 120, 233, 197, 103, 197, - 196, 85, 120, 120, 196, 196, 105, 43, 196, 280, - 280, 43, 84, 196, 196, 197, 280, 196, 43, 43, - 196, 81, 215, 23, 23, 78, 197, 23, 196, 250, - 197, 197, 279, 279, 197, 252, 253, 279, 279, 197, - 197, 77, 71, 197, 279, 23, 197, 160, 68, 26, - 26, 160, 160, 26, 197, 26, 23, 268, 67, 234, - 23, 23, 211, 234, 23, 274, 234, 66, 23, 23, - 234, 26, 107, 23, 108, 198, 198, 109, 207, 198, - 114, 198, 26, 115, 23, 119, 26, 26, 64, 121, - 26, 35, 35, 35, 35, 26, 26, 198, 52, 26, - 29, 29, 26, 51, 29, 50, 29, 127, 198, 132, - 26, 36, 198, 198, 307, 307, 198, 133, 307, 136, - 307, 198, 198, 138, 192, 198, 139, 33, 198, 34, - 34, 34, 34, 29, 140, 142, 198, 29, 29, 305, - 305, 29, 315, 305, 144, 305, 29, 307, 16, 327, - 29, 307, 307, 199, 199, 307, 328, 199, 330, 199, - 307, 29, 297, 297, 307, 331, 332, 297, 297, 337, - 153, 175, 305, 154, 297, 307, 305, 305, 9, 288, - 305, 28, 28, 28, 28, 305, 199, 288, 352, 305, - 199, 199, 8, 356, 199, 298, 298, 173, 367, 199, - 305, 172, 298, 199, 369, 200, 200, 3, 2, 200, - 157, 200, 263, nil, 199, 288, 288, 288, 288, 288, - 288, nil, 288, 288, nil, nil, nil, 200, 298, 288, - nil, nil, 298, 298, nil, nil, 298, nil, 200, nil, - nil, 298, 200, 200, nil, 298, 200, 4, 4, 4, - 4, 200, 200, 39, 39, 200, 298, 39, 200, 39, - 293, 293, 293, 293, 293, 293, 200, 293, 293, nil, - 283, 283, 283, 283, 293, 39, nil, 283, 283, 201, - 201, nil, nil, 201, 283, 201, 39, nil, nil, nil, - 39, 39, nil, nil, 39, nil, nil, nil, nil, 39, - 39, 201, nil, 39, nil, nil, 39, nil, nil, 46, - 46, nil, 201, 46, 39, 46, 201, 201, nil, nil, - 201, nil, nil, nil, nil, 201, 201, nil, nil, 201, - nil, 46, 201, nil, nil, 47, 47, nil, nil, 47, - 201, 47, 46, nil, nil, nil, 46, 46, nil, nil, - 46, nil, nil, nil, nil, 46, 46, 47, nil, 46, - 48, 48, 46, nil, 48, nil, 48, nil, 47, nil, - 46, nil, 47, 47, 49, 49, 47, nil, 49, nil, - nil, 47, 47, nil, nil, 47, nil, nil, 47, nil, - nil, nil, nil, 48, nil, nil, 47, 48, 48, 176, - 176, 48, nil, 176, nil, 176, 48, 49, nil, nil, - 48, 49, 49, nil, nil, 49, nil, nil, nil, nil, - 49, 48, nil, nil, 49, 203, 203, nil, nil, 203, - nil, 203, 176, nil, nil, 49, 176, 176, nil, nil, - 176, nil, nil, nil, nil, 176, nil, 203, nil, 176, - nil, 204, 204, nil, nil, 204, nil, 204, 203, nil, - 176, nil, 203, 203, nil, nil, 203, nil, nil, nil, - nil, 203, 203, 204, nil, 203, nil, nil, 203, nil, - nil, 205, 205, nil, 204, 205, 203, 205, 204, 204, - nil, nil, 204, nil, nil, nil, nil, 204, 204, nil, - nil, 204, nil, 205, 204, nil, nil, 100, 100, nil, - nil, 100, 204, 100, 205, nil, nil, nil, 205, 205, - nil, nil, 205, nil, nil, nil, nil, 205, 205, 100, - nil, 205, 63, 63, 205, nil, 63, nil, 63, nil, - 100, nil, 205, nil, 100, 100, nil, nil, 100, nil, - nil, nil, nil, 100, 100, nil, nil, 100, 208, 208, - 100, nil, 208, nil, 208, 63, nil, nil, 100, 63, - 63, nil, nil, 63, nil, nil, nil, nil, 63, nil, - 208, nil, 63, nil, 209, 209, nil, nil, 209, nil, - 209, 208, nil, 63, nil, 208, 208, nil, nil, 208, - nil, nil, 269, 269, 208, 208, 209, nil, 208, 276, - 276, 208, nil, 276, nil, 276, nil, 209, nil, 208, - nil, 209, 209, nil, nil, 209, nil, nil, nil, nil, - 209, 209, nil, nil, 209, 269, nil, 209, nil, 269, - 269, nil, 276, 269, nil, 209, 276, 276, 269, nil, - 276, nil, 269, nil, nil, 276, 256, 256, nil, 276, - 256, nil, 256, 269, nil, nil, nil, nil, nil, nil, - 276, nil, nil, nil, nil, 74, 74, nil, 256, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 256, - nil, nil, nil, 256, 256, nil, nil, 256, 74, nil, - 254, 254, 256, 256, nil, nil, 256, nil, 74, 256, - nil, nil, 74, 74, nil, nil, 74, 256, 75, 75, - 74, 74, 75, 254, 75, 74, nil, nil, nil, nil, - nil, nil, nil, 254, nil, nil, 74, 254, 254, nil, - 75, 254, nil, 248, 248, 254, 254, 248, nil, 248, - 254, 75, nil, 245, 245, 75, 75, nil, nil, 75, - nil, 254, nil, nil, 75, 75, nil, nil, 75, 244, - 244, 75, nil, nil, nil, nil, 248, nil, nil, 75, - 248, 248, nil, nil, 248, nil, 245, nil, nil, 248, - 245, 245, nil, 248, 245, nil, 225, 225, nil, 245, - 225, nil, 244, 245, 248, nil, 244, 244, nil, nil, - 244, nil, 82, 82, 245, 244, 82, nil, 82, 244, - nil, nil, 210, 210, nil, nil, 210, nil, 210, 225, - 244, nil, nil, 225, 225, nil, nil, 225, nil, nil, - nil, nil, 225, nil, 210, 82, 225, nil, nil, 82, - 82, nil, nil, 82, nil, 210, nil, 225, 82, 210, - 210, nil, 82, 210, nil, nil, nil, nil, 210, 210, - 213, 213, 210, 82, 213, 210, 213, 284, 284, 284, - 284, 284, 284, 210, 284, 284, nil, nil, nil, 102, - 102, 284, 213, 102, 102, 102, 230, 230, nil, nil, - 230, nil, 230, 213, nil, nil, nil, 213, 213, nil, - nil, 213, nil, nil, nil, nil, 213, 213, 214, 214, - 213, nil, 102, 213, nil, nil, 102, 102, nil, 230, - 102, 213, nil, 230, 230, 102, nil, 230, nil, 102, - nil, nil, 230, 228, 228, nil, 230, 228, nil, 228, - 102, 214, nil, nil, nil, 214, 214, 230, nil, 214, - nil, 94, 94, nil, 214, 94, nil, 94, 214, nil, - nil, nil, nil, nil, nil, nil, 228, nil, nil, 214, - 228, 228, nil, 94, 228, nil, nil, nil, nil, 228, - nil, 97, 97, 228, 94, 97, nil, 97, 94, 94, - nil, nil, 94, nil, 228, nil, nil, 94, 94, nil, - nil, 94, nil, 97, 94, nil, nil, 206, 206, nil, - nil, 206, 94, 206, 97, nil, nil, nil, 97, 97, - nil, nil, 97, nil, nil, nil, nil, 97, 97, 206, - nil, 97, nil, nil, 97, nil, nil, nil, nil, nil, - 206, nil, 97, nil, 206, 206, 111, nil, 206, nil, - nil, nil, nil, 206, 206, 111, 111, 206, nil, nil, - 206, nil, nil, nil, 111, 111, 111, 111, 206, nil, - 124, 124, nil, nil, nil, nil, nil, nil, nil, 124, - 124, 124, 124, nil, nil, nil, nil, nil, 111, 111, - nil, nil, 111, 111, 111, 111, 111, 111, nil, 111, - 111, nil, nil, 124, 124, nil, 111, 124, 124, 124, - 124, 124, 124, nil, 124, 124, 130, 130, nil, nil, - nil, 124, nil, nil, nil, 130, 130, 130, 130, nil, - nil, 131, 131, nil, nil, nil, nil, nil, nil, nil, - 131, 131, 131, 131, nil, nil, nil, nil, nil, 130, - 130, nil, nil, 130, 130, 130, 130, 130, 130, nil, - 130, 130, nil, nil, 131, 131, nil, 130, 131, 131, - 131, 131, 131, 131, nil, 131, 131, 287, 287, nil, - nil, nil, 131, nil, nil, nil, 287, 287, 287, 287, - nil, nil, 186, 186, nil, nil, nil, nil, nil, nil, - 186, 186, 186, 186, 186, nil, nil, nil, nil, nil, - nil, 287, nil, nil, 287, 287, 287, 287, 287, 287, - nil, 287, 287, nil, nil, 186, 186, nil, 287, 186, - 186, 186, 186, 186, 186, nil, 186, 186, 291, 291, - nil, nil, nil, 186, nil, nil, nil, 291, 291, 291, - 291, nil, nil, 19, 292, 19, 19, nil, 19, 19, - nil, 19, 292, 19, nil, 19, nil, 19, nil, nil, - 19, 19, nil, 289, nil, 291, 291, 291, 291, 291, - 291, 289, 291, 291, nil, nil, nil, nil, nil, 291, - 292, 292, 292, 292, 292, 292, nil, 292, 292, nil, - nil, 237, nil, nil, 292, nil, nil, nil, nil, 289, - 289, 289, 289, 289, 289, nil, 289, 289, nil, nil, - 372, nil, 237, 289, 237, 237, nil, 237, 237, nil, - 237, nil, 237, nil, 237, nil, 237, nil, nil, 237, - 237, 372, 378, 372, 372, nil, 372, 372, nil, 372, - nil, 372, nil, 372, nil, 372, nil, nil, 372, 372, - nil, 212, nil, 378, nil, 378, 378, nil, 378, 378, - nil, 378, nil, 378, nil, 378, nil, 378, nil, nil, - 378, 378, 212, 323, 212, 212, nil, 212, 212, nil, - 212, nil, 212, nil, 212, nil, 212, nil, nil, 212, - 212, nil, 374, nil, 323, nil, 323, 323, nil, 323, - 323, nil, 323, nil, 323, nil, 323, nil, 323, nil, - nil, 323, 323, 374, 380, 374, 374, nil, 374, 374, - nil, 374, nil, 374, nil, 374, nil, 374, nil, nil, - 374, 374, nil, 303, nil, 380, nil, 380, 380, nil, - 380, 380, nil, 380, nil, 380, nil, 380, nil, 380, - nil, nil, 380, 380, 303, 319, 303, 303, nil, 303, - 303, nil, 303, nil, 303, nil, 303, nil, 303, nil, - nil, 303, 303, nil, 362, nil, 319, nil, 319, 319, - nil, 319, 319, nil, 319, nil, 319, nil, 319, nil, - 319, nil, nil, 319, 319, 362, 217, 362, 362, nil, - 362, 362, nil, 362, nil, 362, nil, 362, nil, 362, - nil, nil, 362, 362, nil, 295, nil, 217, nil, 217, - 217, nil, 217, 217, nil, 217, nil, 217, nil, 217, - nil, 217, nil, nil, 217, 217, 295, nil, 295, 295, - nil, 295, 295, nil, 295, nil, 295, nil, 295, nil, - 295, nil, nil, 295, 295, 0, nil, 0, 0, nil, - 0, 0, nil, 0, nil, 0, nil, 0, nil, 0, - nil, nil, 0, 0 ] + 164, 164, 158, 154, 301, 27, 56, 27, 81, 214, + 285, 285, 301, 164, 164, 239, 293, 285, 18, 206, + 27, 213, 164, 164, 164, 164, 81, 206, 175, 175, + 194, 56, 175, 194, 175, 368, 368, 214, 214, 157, + 158, 293, 293, 158, 27, 154, 164, 164, 285, 144, + 164, 164, 164, 164, 164, 164, 18, 164, 164, 18, + 85, 175, 144, 158, 164, 175, 175, 272, 368, 175, + 83, 261, 368, 368, 175, 272, 368, 157, 175, 18, + 157, 368, 161, 161, 261, 368, 161, 216, 161, 175, + 1, 82, 356, 356, 1, 218, 368, 219, 203, 163, + 157, 1, 114, 272, 272, 272, 272, 272, 272, 203, + 272, 272, 163, 114, 203, 161, 122, 272, 114, 161, + 161, 122, 192, 161, 221, 356, 192, 192, 161, 356, + 356, 220, 161, 356, 290, 335, 335, 221, 356, 335, + 111, 335, 356, 161, 309, 290, 331, 331, 11, 309, + 290, 111, 11, 356, 329, 329, 111, 335, 329, 11, + 329, 48, 48, 103, 103, 48, 334, 48, 335, 334, + 103, 200, 335, 335, 262, 262, 335, 263, 263, 262, + 262, 335, 335, 48, 263, 335, 262, 329, 335, 224, + 280, 329, 329, 280, 48, 329, 335, 197, 48, 48, + 329, 103, 48, 227, 329, 295, 295, 48, 48, 87, + 229, 48, 307, 307, 48, 329, 307, 33, 307, 306, + 306, 33, 48, 306, 230, 306, 299, 299, 33, 33, + 225, 80, 232, 299, 225, 77, 46, 225, 295, 234, + 46, 225, 295, 295, 235, 307, 295, 46, 46, 307, + 307, 295, 306, 307, 75, 295, 306, 306, 307, 299, + 306, 212, 307, 299, 299, 306, 295, 299, 8, 306, + 23, 23, 299, 307, 23, 74, 299, 8, 8, 66, + 306, 249, 42, 252, 264, 264, 42, 299, 65, 166, + 166, 264, 23, 42, 42, 26, 26, 64, 89, 26, + 201, 26, 94, 23, 201, 201, 187, 23, 23, 169, + 101, 23, 102, 169, 169, 23, 23, 26, 105, 183, + 23, 53, 166, 52, 294, 294, 166, 166, 26, 50, + 166, 23, 26, 26, 166, 166, 26, 143, 106, 166, + 107, 26, 26, 29, 29, 26, 108, 29, 26, 29, + 166, 110, 279, 167, 167, 113, 26, 294, 115, 167, + 283, 294, 294, 281, 281, 294, 37, 211, 281, 281, + 294, 211, 211, 116, 294, 281, 29, 288, 170, 170, + 29, 29, 119, 32, 29, 294, 167, 121, 127, 29, + 167, 167, 297, 29, 167, 17, 287, 287, 133, 167, + 287, 170, 287, 167, 29, 3, 3, 3, 3, 304, + 13, 170, 12, 134, 167, 170, 170, 136, 320, 170, + 324, 172, 172, 170, 170, 172, 159, 172, 170, 287, + 140, 141, 155, 287, 287, 337, 342, 287, 346, 170, + 347, 349, 287, 172, 350, 351, 287, 45, 45, 5, + 357, 45, 142, 45, 172, 367, 147, 287, 172, 172, + 369, 2, 172, 4, 4, 4, 4, 172, 172, 45, + 146, 172, 379, 381, 172, nil, nil, 173, 173, nil, + 45, 173, 172, 173, 45, 45, nil, nil, 45, 31, + 31, 31, 31, 45, 45, nil, nil, 45, nil, 173, + 45, nil, nil, 47, 47, nil, nil, 47, 45, 47, + 173, nil, nil, nil, 173, 173, nil, nil, 173, 6, + 6, 6, 6, 173, 173, 47, nil, 173, nil, nil, + 173, nil, nil, 174, 174, nil, 47, 174, 173, 174, + 47, 47, nil, nil, 47, nil, nil, nil, nil, 47, + 47, nil, nil, 47, nil, 174, 47, nil, nil, 49, + 49, nil, nil, 49, 47, 49, 174, nil, nil, nil, + 174, 174, nil, nil, 174, nil, nil, 51, 51, 174, + 174, 51, nil, 174, 176, 176, 174, nil, 176, nil, + 176, nil, 49, nil, 174, nil, 49, 49, nil, nil, + 49, nil, nil, nil, nil, 49, 176, nil, nil, 49, + 51, nil, nil, nil, 51, 51, nil, 176, 51, nil, + 49, 176, 176, 51, nil, 176, nil, 51, nil, nil, + 176, 176, nil, nil, 176, 177, 177, 176, 51, 177, + nil, 177, nil, nil, nil, 176, nil, nil, nil, nil, + nil, nil, nil, nil, 112, 112, nil, 177, 112, nil, + 112, 259, 259, nil, nil, 259, nil, 259, 177, nil, + nil, nil, 177, 177, nil, nil, 177, nil, nil, 254, + 254, 177, 177, nil, nil, 177, nil, 112, 177, nil, + nil, 112, 112, nil, 259, 112, 177, nil, 259, 259, + 112, nil, 259, nil, 112, 70, 70, 259, nil, nil, + nil, 259, 254, nil, nil, 112, 254, 254, nil, nil, + 254, nil, 259, nil, nil, 254, 242, 242, 70, 254, + 242, nil, 242, nil, nil, nil, nil, nil, 70, nil, + 254, nil, 70, 70, nil, nil, 70, nil, 242, nil, + 70, 70, 71, 71, nil, 70, 71, nil, 71, 242, + nil, nil, nil, 242, 242, nil, 70, 242, nil, nil, + nil, nil, 242, 242, 71, nil, 242, 240, 240, 242, + nil, nil, nil, nil, nil, 71, nil, 242, nil, 71, + 71, nil, nil, 71, nil, nil, nil, nil, 71, 71, + 240, nil, 71, 178, 178, 71, nil, 178, nil, 178, + 240, nil, nil, 71, 240, 240, nil, nil, 240, nil, + nil, nil, 240, 240, nil, 178, nil, 240, 233, 233, + nil, nil, 233, nil, 233, nil, 178, nil, 240, nil, + 178, 178, 78, 78, 178, nil, 78, nil, 78, 178, + 178, nil, nil, 178, nil, nil, 178, nil, nil, nil, + nil, 233, nil, nil, 178, 233, 233, 231, 231, 233, + nil, 231, nil, 231, 233, 78, nil, nil, 233, 78, + 78, 228, 228, 78, nil, 228, nil, nil, 78, 233, + nil, nil, 78, nil, nil, nil, nil, nil, nil, nil, + 231, nil, nil, 78, 231, 231, nil, nil, 231, nil, + nil, 215, 215, 231, 228, nil, nil, 231, 228, 228, + nil, nil, 228, nil, nil, nil, nil, 228, 231, 179, + 179, 228, nil, 179, nil, 179, nil, nil, nil, nil, + nil, nil, 228, nil, 215, nil, nil, nil, 215, 215, + nil, 179, 215, nil, nil, nil, nil, 215, nil, 185, + 185, 215, 179, 185, nil, 185, 179, 179, nil, nil, + 179, nil, 215, nil, nil, 179, 179, nil, nil, 179, + nil, 185, 179, nil, nil, 181, 181, nil, nil, 181, + 179, 181, 185, nil, nil, nil, 185, 185, nil, nil, + 185, nil, nil, nil, nil, 185, 185, 181, nil, 185, + nil, nil, 185, nil, nil, 189, 189, nil, 181, 189, + 185, 189, 181, 181, nil, nil, 181, nil, nil, nil, + nil, 181, 181, nil, nil, 181, nil, 189, 181, nil, + nil, 90, 90, nil, nil, 90, 181, 90, 189, nil, + nil, nil, 189, 189, nil, nil, 189, nil, nil, nil, + nil, 189, 189, 90, nil, 189, nil, nil, 189, nil, + nil, 182, 182, nil, 90, 182, 189, 182, 90, 90, + nil, nil, 90, nil, nil, nil, nil, 90, 90, nil, + nil, 90, nil, 182, 90, nil, nil, 184, 184, nil, + nil, 184, 90, 184, 182, nil, nil, nil, 182, 182, + nil, nil, 182, nil, nil, nil, nil, 182, 182, 184, + nil, 182, nil, nil, 182, nil, nil, 95, 95, nil, + 184, 95, 182, 95, 184, 184, nil, nil, 184, nil, + nil, nil, nil, 184, 184, nil, nil, 184, nil, 95, + 184, nil, nil, 99, 99, nil, nil, 99, 184, 99, + 95, nil, nil, nil, 95, 95, nil, nil, 95, nil, + nil, nil, nil, 95, 95, 99, nil, 95, 100, 100, + 95, nil, 100, 100, 100, nil, 99, nil, 95, nil, + 99, 99, nil, nil, 99, nil, nil, nil, nil, 99, + 99, nil, nil, 99, 186, 186, 99, nil, 186, nil, + 186, 100, nil, nil, 99, 100, 100, nil, nil, 100, + nil, nil, nil, nil, 100, nil, 186, nil, 100, nil, + 180, 180, nil, nil, 180, nil, 180, 186, nil, 100, + nil, 186, 186, nil, nil, 186, nil, nil, nil, nil, + 186, 186, 180, nil, 186, nil, nil, 186, nil, nil, + nil, nil, nil, 180, nil, 186, nil, 180, 180, 91, + nil, 180, nil, nil, nil, nil, 180, 180, 91, 91, + 180, nil, nil, 180, nil, nil, nil, 91, 91, 91, + 91, 180, nil, 190, 190, nil, nil, nil, nil, nil, + nil, 190, 190, 190, 190, 190, nil, nil, nil, nil, + nil, 91, 91, nil, nil, 91, 91, 91, 91, 91, + 91, nil, 91, 91, nil, nil, 190, 190, nil, 91, + 190, 190, 190, 190, 190, 190, nil, 190, 190, 274, + 274, nil, nil, nil, 190, nil, nil, nil, 274, 274, + 274, 274, nil, nil, 132, 132, nil, nil, nil, nil, + nil, nil, nil, 132, 132, 132, 132, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 274, 274, 274, 274, + 274, 274, nil, 274, 274, nil, nil, 132, 132, nil, + 274, 132, 132, 132, 132, 132, 132, nil, 132, 132, + 131, 131, nil, nil, nil, 132, nil, nil, nil, 131, + 131, 131, 131, nil, nil, 270, 270, nil, nil, nil, + nil, nil, nil, nil, 270, 270, 270, 270, nil, nil, + nil, nil, nil, 131, 131, nil, nil, 131, 131, 131, + 131, 131, 131, nil, 131, 131, nil, nil, nil, 270, + nil, 131, 270, 270, 270, 270, 270, 270, nil, 270, + 270, 129, 129, nil, nil, nil, 270, nil, nil, nil, + 129, 129, 129, 129, nil, nil, nil, 269, nil, 276, + 276, 276, 276, 276, 276, 269, 276, 276, nil, nil, + nil, nil, nil, 276, 129, 129, 275, nil, 129, 129, + 129, 129, 129, 129, 275, 129, 129, nil, nil, nil, + nil, 271, 129, 269, 269, 269, 269, 269, 269, 271, + 269, 269, nil, nil, nil, nil, nil, 269, nil, nil, + nil, nil, 275, 275, 275, 275, 275, 275, nil, 275, + 275, 188, nil, nil, nil, nil, 275, 271, 271, 271, + 271, 271, 271, nil, 271, 271, nil, nil, nil, nil, + 238, 271, 188, nil, 188, 188, nil, 188, 188, nil, + 188, nil, 188, nil, 188, nil, 188, nil, nil, 188, + 188, 238, 311, 238, 238, nil, 238, 238, nil, 238, + nil, 238, nil, 238, nil, 238, nil, nil, 238, 238, + nil, 375, nil, 311, nil, 311, 311, nil, 311, 311, + nil, 311, nil, 311, nil, 311, nil, 311, nil, nil, + 311, 311, 375, 372, 375, 375, nil, 375, 375, nil, + 375, nil, 375, nil, 375, nil, 375, nil, nil, 375, + 375, nil, 362, nil, 372, nil, 372, 372, nil, 372, + 372, nil, 372, nil, 372, nil, 372, nil, 372, nil, + nil, 372, 372, 362, 217, 362, 362, nil, 362, 362, + nil, 362, nil, 362, nil, 362, nil, 362, nil, nil, + 362, 362, nil, nil, nil, 217, nil, 217, 217, nil, + 217, 217, nil, 217, nil, 217, nil, 217, nil, 217, + nil, nil, 217, 217, 0, nil, 0, 0, nil, 0, + 0, nil, 0, nil, 0, nil, 0, nil, 0, nil, + nil, 0, 0, 20, nil, 20, 20, nil, 20, 20, + nil, 20, nil, 20, nil, 20, nil, 20, nil, nil, + 20, 20, 278, nil, 278, 278, nil, 278, 278, nil, + 278, nil, 278, nil, 278, nil, 278, nil, nil, 278, + 278, 267, 267, 267, 267, 267, 267, nil, 267, 267, + 266, 266, 266, 266, nil, 267, nil, 266, 266, 268, + 268, 268, 268, nil, 266, nil, 268, 268, nil, nil, + nil, nil, nil, 268 ] racc_action_pointer = [ - 1795, 163, 443, 413, 433, nil, nil, 3, 434, 420, - nil, nil, 142, nil, nil, nil, 398, 26, nil, 1483, - nil, nil, 80, 271, nil, nil, 297, nil, 367, 348, - 166, nil, nil, 375, 315, 277, 337, nil, nil, 501, - nil, nil, nil, 221, nil, nil, 557, 583, 608, 622, - 315, 329, 348, nil, nil, 4, nil, nil, nil, nil, - nil, nil, 97, 780, 298, -9, 309, 302, 275, nil, - nil, 286, nil, nil, 923, 966, nil, 279, 269, nil, - 6, 248, 1060, nil, 239, 245, -3, 177, nil, nil, - 149, 137, nil, nil, 1209, 10, nil, 1239, nil, nil, - 755, 121, 1137, 225, nil, 233, 3, 299, 301, 304, - nil, 1298, nil, nil, 322, 325, nil, nil, nil, 323, - 205, 331, 144, nil, 1313, nil, nil, 351, nil, nil, - 1359, 1374, 352, 344, nil, nil, 328, nil, 350, 364, - 361, nil, 362, 79, 374, nil, nil, nil, nil, nil, - nil, nil, -9, 408, 386, nil, 2, 452, 30, nil, - 251, nil, nil, 84, nil, 50, nil, nil, nil, nil, - nil, 174, 439, 436, -14, 381, 647, nil, 114, nil, - -4, 57, 75, 197, 172, nil, 1435, nil, 225, nil, - nil, nil, 363, nil, nil, 213, 215, 241, 323, 401, - 453, 527, 32, 673, 699, 729, 1265, 265, 806, 832, - 1070, 249, 1612, 1118, 1166, 270, nil, 1757, 24, 24, - 91, 121, nil, nil, 142, 1044, 126, 161, 1191, 147, - 1144, 198, 233, 238, 273, nil, nil, 1552, nil, 39, - nil, nil, nil, 66, 1017, 1001, nil, nil, 991, nil, - 270, nil, 273, 279, 948, nil, 904, nil, nil, nil, - nil, nil, nil, 451, nil, nil, nil, nil, 283, 850, - nil, nil, -5, nil, 308, nil, 857, 8, nil, 226, - 198, 67, nil, 466, 1073, 86, 172, 1420, 411, 1515, - nil, 1481, 1496, 456, nil, 1776, -4, 356, 443, nil, - 145, nil, nil, 1694, nil, 387, nil, 362, 129, nil, - nil, nil, nil, nil, nil, 380, nil, nil, nil, 1716, - nil, nil, nil, 1634, nil, nil, nil, 376, 383, nil, - 385, 392, 393, nil, nil, nil, nil, 410, nil, nil, - nil, 153, nil, 183, nil, nil, nil, nil, nil, 51, - nil, 128, 430, nil, nil, 110, 435, nil, nil, nil, - nil, nil, 1735, nil, nil, nil, nil, 439, 59, 445, - nil, nil, 1571, nil, 1653, nil, nil, nil, 1593, nil, - 1675, nil, nil, nil ] + 1674, 54, 417, 341, 399, 434, 455, nil, 262, nil, + nil, 112, 404, 402, nil, nil, nil, 395, 16, nil, + 1693, nil, nil, 268, nil, nil, 293, -1, nil, 341, + nil, 425, 381, 181, nil, nil, nil, 342, nil, nil, + nil, nil, 246, nil, nil, 445, 200, 501, 159, 557, + 305, 575, 283, 321, nil, nil, -6, nil, nil, nil, + nil, nil, nil, nil, 291, 265, 273, nil, nil, nil, + 703, 750, nil, nil, 269, 242, nil, 212, 840, nil, + 208, 2, 68, 64, nil, 37, nil, 186, nil, 275, + 1039, 1261, nil, nil, 279, 1125, nil, nil, nil, 1151, + 1176, 287, 289, 161, nil, 295, 315, 317, 323, nil, + 343, 116, 652, 315, 78, 350, 361, nil, nil, 374, + nil, 379, 81, nil, nil, nil, nil, 382, nil, 1444, + nil, 1383, 1337, 391, 376, nil, 394, nil, nil, nil, + 389, 408, 440, 314, 38, nil, 447, 436, nil, nil, + nil, nil, nil, nil, -8, 420, nil, 37, 0, 418, + nil, 80, nil, 87, -4, nil, 287, 351, nil, 302, + 376, nil, 419, 475, 531, 26, 582, 633, 801, 927, + 1228, 983, 1069, 256, 1095, 957, 1202, 243, 1532, 1013, + 1276, nil, 115, nil, 21, nil, nil, 186, nil, nil, + 131, 254, nil, 74, nil, nil, 1, nil, nil, nil, + nil, 360, 249, 10, -13, 909, 85, 1655, 80, 82, + 106, 112, nil, nil, 181, 194, nil, 194, 879, 170, + 215, 865, 192, 826, 199, 235, nil, nil, 1551, 8, + 775, nil, 724, nil, nil, nil, nil, nil, nil, 270, + nil, nil, 259, nil, 677, nil, nil, nil, nil, 659, + nil, 59, 118, 116, 223, nil, 1716, 1707, 1725, 1459, + 1398, 1493, 49, nil, 1322, 1478, 1425, nil, 1712, 343, + 159, 307, nil, 353, nil, 8, nil, 394, 365, nil, + 110, nil, nil, -9, 322, 203, nil, 383, nil, 224, + nil, -8, nil, nil, 400, nil, 217, 210, nil, 109, + nil, 1573, nil, nil, nil, nil, nil, nil, nil, nil, + 406, nil, nil, nil, 411, nil, nil, nil, nil, 152, + nil, 135, nil, nil, 135, 133, nil, 427, nil, nil, + nil, nil, 427, nil, nil, nil, 415, 417, nil, 418, + 421, 422, nil, nil, nil, nil, 90, 442, nil, nil, + nil, nil, 1633, nil, nil, nil, nil, 446, 33, 451, + nil, nil, 1614, nil, nil, 1592, nil, nil, nil, 463, + nil, 464, nil, nil, nil ] racc_action_default = [ - -196, -233, -233, -50, -233, -8, -9, -233, -233, -22, - -10, -187, -188, -11, -185, -12, -233, -233, -13, -1, - -14, -2, -233, -186, -15, -3, -233, -16, -5, -233, - -233, -17, -6, -233, -18, -7, -196, -188, -186, -233, - -51, -26, -27, -233, -24, -25, -233, -233, -233, -85, - -92, -196, -233, -195, -193, -196, -189, -191, -192, -221, - -194, -4, -196, -233, -85, -196, -53, -231, -42, -174, - -43, -213, -117, -33, -233, -233, -44, -31, -74, -32, - -233, -36, -233, -122, -37, -233, -73, -38, -172, -72, - -39, -40, -173, -41, -233, -103, -111, -233, -132, -112, - -233, -104, -233, -108, -110, -105, -233, -114, -106, -113, - -109, -233, -125, -107, -233, -233, -49, -175, -176, -178, - -233, -233, -197, -198, -83, -19, -22, -186, -21, -23, - -82, -84, -233, -75, -86, -81, -70, -74, -76, -219, - -79, -68, -77, -73, -233, -171, -170, -80, -78, -90, - -91, -93, -233, -219, -196, 384, -233, -233, -233, -207, - -233, -57, -213, -196, -59, -233, -66, -65, -56, -73, - -95, -233, -219, -233, -233, -92, -233, -30, -233, -118, - -233, -233, -233, -233, -233, -142, -233, -149, -233, -216, - -229, -225, -233, -228, -224, -233, -233, -233, -233, -233, - -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, - -233, -233, -233, -233, -233, -233, -20, -233, -206, -233, - -204, -233, -201, -230, -233, -71, -220, -233, -233, -85, - -233, -220, -233, -233, -233, -209, -190, -233, -208, -233, - -54, -62, -61, -233, -233, -233, -217, -218, -233, -124, - -233, -55, -219, -233, -233, -28, -233, -120, -119, -35, - -34, -168, -166, -233, -169, -160, -167, -161, -73, -233, - -123, -116, -233, -152, -218, -214, -233, -233, -222, -137, - -139, -138, -133, -140, -144, -141, -146, -151, -148, -145, - -134, -150, -147, -143, -135, -233, -128, -136, -233, -154, - -233, -158, -177, -233, -180, -233, -199, -233, -233, -200, - -45, -69, -87, -46, -88, -219, -89, -94, -48, -233, - -211, -210, -212, -233, -184, -58, -60, -97, -98, -63, - -102, -99, -100, -101, -64, -96, -47, -233, -232, -29, - -121, -233, -163, -219, -115, -215, -227, -226, -223, -128, - -127, -233, -233, -155, -153, -233, -233, -179, -205, -203, - -202, -67, -233, -182, -183, -52, -165, -218, -233, -233, - -126, -129, -233, -159, -233, -181, -164, -162, -233, -131, - -233, -157, -130, -156 ] + -197, -234, -51, -19, -8, -234, -234, -9, -234, -10, + -188, -189, -234, -23, -11, -186, -12, -234, -234, -13, + -1, -14, -2, -187, -15, -3, -234, -234, -16, -234, + -17, -6, -234, -234, -18, -7, -189, -197, -187, -52, + -27, -28, -234, -25, -26, -234, -234, -234, -234, -234, + -197, -86, -93, -234, -196, -194, -197, -190, -192, -193, + -222, -195, -4, -42, -232, -43, -214, -175, -118, -44, + -234, -234, -45, -34, -75, -32, -33, -234, -234, -123, + -37, -74, -38, -234, -73, -39, -173, -40, -174, -41, + -234, -234, -126, -108, -104, -234, -112, -133, -113, -234, + -234, -105, -109, -234, -111, -106, -115, -107, -114, -110, + -54, -197, -234, -86, -197, -234, -179, -176, -177, -234, + -50, -234, -198, -199, -24, -21, -23, -187, -22, -84, + -20, -83, -85, -234, -197, -79, -76, -87, -82, -75, + -71, -77, -220, -80, -74, -69, -78, -234, -172, -171, + -81, -91, -92, -94, -234, -220, 385, -234, -234, -234, + -208, -234, -31, -234, -234, -119, -234, -234, -96, -234, + -234, -143, -234, -234, -234, -234, -234, -234, -234, -234, + -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, + -234, -150, -234, -217, -234, -230, -226, -234, -229, -225, + -93, -234, -214, -197, -58, -60, -234, -67, -57, -74, + -66, -234, -220, -234, -234, -234, -234, -234, -207, -205, + -234, -234, -202, -231, -234, -234, -210, -234, -72, -221, + -234, -234, -86, -234, -221, -234, -191, -209, -234, -234, + -234, -29, -234, -121, -120, -36, -35, -169, -167, -234, + -170, -161, -74, -168, -234, -162, -218, -219, -124, -234, + -117, -234, -138, -140, -139, -134, -141, -145, -142, -147, + -152, -149, -146, -135, -151, -148, -144, -136, -5, -234, + -129, -137, -153, -219, -215, -234, -223, -234, -220, -55, + -234, -63, -62, -234, -234, -234, -125, -234, -56, -234, + -155, -234, -159, -178, -234, -181, -234, -234, -200, -234, + -201, -234, -212, -213, -211, -46, -70, -88, -47, -89, + -220, -90, -95, -49, -234, -185, -233, -30, -122, -234, + -164, -220, -97, -116, -129, -234, -128, -234, -216, -227, + -224, -228, -234, -59, -61, -102, -98, -99, -64, -103, + -100, -101, -65, -48, -156, -154, -234, -234, -180, -206, + -204, -203, -234, -183, -68, -184, -166, -219, -234, -234, + -127, -130, -234, -53, -160, -234, -182, -165, -163, -234, + -132, -234, -158, -131, -157 ] racc_goto_table = [ - 22, 9, 68, 112, 53, 118, 61, 36, 91, 222, - 19, 267, 70, 93, 2, 227, 139, 191, 51, 22, - 9, 179, 77, 56, 73, 149, 21, 141, 133, 232, - 115, 172, 153, 2, 146, 263, 125, 116, 135, 148, - 147, 299, 129, 22, 126, 260, 160, 350, 250, 174, - 128, 171, 43, 68, 121, 329, 334, 298, 368, 91, - 258, 265, 123, 70, 93, 317, 343, 301, 136, 154, - 183, 119, 224, 178, 233, 73, 55, 123, 157, 66, - 238, 159, 120, 219, 221, 190, 325, 321, 195, 16, - 188, nil, nil, nil, nil, nil, nil, nil, 342, nil, - 370, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, 216, nil, nil, nil, nil, 260, 129, - 22, 126, 263, nil, nil, 353, nil, 128, 337, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 81, - nil, nil, nil, 53, nil, 53, nil, 243, nil, nil, - 149, 301, nil, nil, nil, nil, nil, 252, nil, nil, - 68, 261, 236, 68, nil, 138, 91, 146, nil, 91, - 70, 93, nil, 70, 93, nil, nil, nil, 166, nil, - 235, 166, 259, 272, nil, 73, nil, 302, 347, nil, - 81, 361, nil, 261, 290, 360, 315, 376, 294, 146, - nil, 312, 340, 311, 133, nil, 149, nil, 373, nil, - 146, nil, 22, 9, 135, 148, 147, 22, 9, 369, - nil, 263, 295, 327, 327, nil, 2, 303, nil, 146, - 146, 2, nil, 68, 333, 333, nil, 22, 9, 91, - 320, 88, nil, 70, 93, nil, nil, 323, 261, nil, - nil, 2, nil, nil, 146, 259, 190, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 88, nil, nil, - nil, nil, nil, nil, nil, 87, nil, 261, nil, 166, - nil, nil, 61, 146, nil, nil, nil, nil, nil, nil, - 61, nil, 88, nil, nil, 22, 9, 81, 262, nil, - 81, 142, nil, 22, 9, nil, nil, nil, nil, 2, - 61, nil, nil, nil, nil, nil, nil, 2, nil, 22, - 9, nil, nil, 22, 9, nil, 87, nil, 371, 362, - 262, nil, nil, 2, 261, nil, nil, 2, nil, nil, - 146, 138, nil, nil, nil, nil, nil, 261, nil, 61, - nil, nil, nil, 146, nil, 166, nil, nil, nil, nil, - 328, 328, 22, 9, 114, 61, nil, 61, nil, 84, - 81, nil, 22, 9, 22, 9, 2, 90, 22, 9, - 22, 9, 378, 132, 380, 262, 2, nil, 2, nil, - nil, nil, 2, nil, 2, 140, nil, nil, 170, 88, - 88, nil, 88, 145, nil, nil, nil, nil, 167, nil, - nil, 167, nil, nil, 262, nil, nil, 170, nil, nil, - 84, nil, nil, nil, nil, nil, nil, nil, 90, nil, - nil, nil, 88, 87, 266, nil, 87, 170, nil, nil, - nil, nil, nil, 88, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, 88, 88, nil, nil, 266, nil, nil, nil, - nil, 262, 88, nil, nil, nil, nil, 142, nil, nil, - nil, nil, nil, nil, 262, nil, nil, 88, nil, nil, - nil, nil, nil, nil, nil, nil, 331, 331, nil, nil, - nil, nil, nil, nil, nil, nil, 87, nil, nil, 167, - nil, 253, nil, nil, nil, nil, 88, nil, nil, nil, - nil, 266, nil, nil, nil, nil, nil, 84, 264, nil, - 84, nil, nil, nil, 282, 90, 145, nil, 90, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 266, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 264, nil, nil, 314, nil, 316, nil, 124, 145, nil, - nil, 140, nil, 88, 130, 131, nil, nil, nil, 145, - nil, nil, nil, 335, nil, 167, 88, nil, nil, nil, - 330, 330, nil, nil, nil, nil, nil, nil, 332, 332, - 84, nil, nil, 180, nil, nil, nil, 266, 90, nil, - nil, 346, nil, nil, nil, 264, nil, nil, nil, nil, - 266, nil, 185, 145, nil, 186, nil, nil, 187, nil, + 27, 13, 5, 37, 62, 255, 249, 20, 118, 196, + 92, 89, 142, 50, 155, 300, 69, 63, 222, 336, + 27, 13, 5, 165, 73, 75, 57, 279, 348, 352, + 246, 151, 145, 119, 343, 150, 121, 230, 65, 149, + 299, 22, 27, 126, 138, 135, 27, 126, 201, 134, + 235, 214, 120, 87, 302, 86, 304, 244, 89, 42, + 169, 128, 46, 69, 63, 128, 136, 251, 368, 331, + 322, 73, 163, 370, 212, 125, 124, 324, 123, 130, + 124, 148, 192, 86, 116, 65, 140, 224, 56, 159, + 227, 123, 330, 249, 211, 237, 220, 160, 221, 354, + 87, 110, 86, 115, 246, 314, 194, 297, 17, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 195, nil, + nil, nil, nil, 133, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 54, nil, nil, nil, 302, nil, + 293, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, 168, nil, 89, 149, nil, nil, 89, 69, + 63, nil, 288, 69, 63, 236, nil, 245, nil, nil, + nil, 73, 261, 82, 168, 226, nil, nil, nil, 151, + nil, 65, 247, 342, nil, 65, 168, nil, 27, 13, + 5, 339, 303, 320, 328, 374, 87, 148, 86, 86, + 87, 143, 86, 149, 80, 361, 377, 249, 317, 316, + nil, 379, 150, 151, 381, 364, 149, 27, 13, 5, + 82, 138, 135, nil, nil, nil, 369, 312, 89, nil, + 247, nil, 141, 69, 63, 239, nil, nil, 27, 13, + 5, 245, 149, 136, nil, 148, nil, 86, nil, 265, + nil, 80, nil, nil, nil, 65, nil, nil, 148, nil, + 86, 210, 62, nil, 210, nil, nil, nil, 85, 247, + 87, nil, 86, 54, 54, nil, nil, nil, 27, 13, + 5, nil, 149, 149, 148, nil, 86, 149, 345, 345, + nil, nil, 207, nil, nil, 207, 146, nil, nil, 273, + 195, nil, nil, 277, nil, 319, nil, 321, nil, 346, + 346, 27, 13, 5, 247, 85, 82, 250, 362, 371, + 82, nil, nil, nil, 351, 351, 86, 86, nil, 148, + nil, 86, nil, 332, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 149, nil, 62, 80, 248, nil, + nil, 80, nil, 210, nil, nil, 149, nil, nil, nil, + nil, 341, 27, 13, 5, 250, nil, nil, nil, nil, + nil, 247, 27, 13, 5, 27, 13, 5, 143, nil, + 359, 360, nil, 247, 207, nil, 148, nil, 86, nil, + 82, nil, 129, nil, 131, 132, 248, nil, 148, nil, + 86, nil, nil, 366, 250, nil, nil, nil, nil, 141, + nil, 85, 253, nil, nil, 85, nil, nil, 164, nil, + nil, 80, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 248, nil, 171, nil, nil, + 210, nil, 190, nil, 349, 349, 191, nil, nil, 250, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 358, nil, 359, nil, 264, nil, nil, nil, nil, nil, - nil, nil, 145, nil, nil, nil, nil, nil, nil, nil, + 253, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, 207, nil, 146, nil, 347, 347, nil, nil, nil, + 248, nil, nil, nil, nil, 85, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 253, + nil, nil, nil, nil, nil, nil, 250, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 250, 262, + 263, 264, nil, 266, 267, 268, 269, 270, 271, 272, + nil, 274, 275, 276, nil, nil, 281, 248, nil, 350, + 350, nil, nil, nil, 253, nil, nil, nil, nil, 248, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, 366, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 264, nil, nil, nil, nil, nil, nil, nil, 145, - nil, nil, nil, nil, 264, nil, nil, nil, nil, nil, - nil, nil, 145, nil, 279, 280, 281, nil, 283, 284, - 285, 286, 287, 288, 289, nil, 291, 292, 293, nil, - nil, 297, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 164, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 180 ] + nil, 253, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 253 ] racc_goto_check = [ - 37, 21, 30, 62, 64, 72, 4, 32, 28, 82, - 2, 70, 31, 29, 52, 36, 35, 85, 32, 37, - 21, 60, 22, 78, 21, 53, 3, 47, 30, 36, - 37, 35, 38, 52, 28, 68, 19, 5, 31, 29, - 50, 66, 7, 37, 21, 23, 41, 63, 36, 41, - 5, 57, 20, 30, 74, 46, 46, 65, 58, 28, - 61, 69, 3, 31, 29, 56, 71, 68, 33, 74, - 57, 73, 34, 22, 75, 21, 76, 3, 77, 40, - 79, 3, 20, 80, 81, 30, 42, 83, 84, 1, - 57, nil, nil, nil, nil, nil, nil, nil, 70, nil, - 63, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, 19, nil, nil, nil, nil, 23, 7, - 37, 21, 68, nil, nil, 66, nil, 5, 36, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 24, - nil, nil, nil, 64, nil, 64, nil, 41, nil, nil, - 53, 68, nil, nil, nil, nil, nil, 38, nil, nil, - 30, 30, 78, 30, nil, 24, 28, 28, nil, 28, - 31, 29, nil, 31, 29, nil, nil, nil, 24, nil, - 3, 24, 21, 22, nil, 21, nil, 72, 85, nil, - 24, 36, nil, 30, 64, 82, 35, 70, 64, 28, - nil, 53, 60, 47, 30, nil, 53, nil, 68, nil, - 28, nil, 37, 21, 31, 29, 50, 37, 21, 36, - nil, 68, 2, 30, 30, nil, 52, 2, nil, 28, - 28, 52, nil, 30, 29, 29, nil, 37, 21, 28, - 32, 49, nil, 31, 29, nil, nil, 2, 30, nil, - nil, 52, nil, nil, 28, 21, 30, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 49, nil, nil, - nil, nil, nil, nil, nil, 26, nil, 30, nil, 24, - nil, nil, 4, 28, nil, nil, nil, nil, nil, nil, - 4, nil, 49, nil, nil, 37, 21, 24, 24, nil, - 24, 26, nil, 37, 21, nil, nil, nil, nil, 52, - 4, nil, nil, nil, nil, nil, nil, 52, nil, 37, - 21, nil, nil, 37, 21, nil, 26, nil, 62, 2, - 24, nil, nil, 52, 30, nil, nil, 52, nil, nil, - 28, 24, nil, nil, nil, nil, nil, 30, nil, 4, - nil, nil, nil, 28, nil, 24, nil, nil, nil, nil, - 24, 24, 37, 21, 54, 4, nil, 4, nil, 25, - 24, nil, 37, 21, 37, 21, 52, 27, 37, 21, - 37, 21, 2, 54, 2, 24, 52, nil, 52, nil, - nil, nil, 52, nil, 52, 25, nil, nil, 54, 49, - 49, nil, 49, 27, nil, nil, nil, nil, 25, nil, - nil, 25, nil, nil, 24, nil, nil, 54, nil, nil, - 25, nil, nil, nil, nil, nil, nil, nil, 27, nil, - nil, nil, 49, 26, 26, nil, 26, 54, nil, nil, - nil, nil, nil, 49, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, 49, 49, nil, nil, 26, nil, nil, nil, - nil, 24, 49, nil, nil, nil, nil, 26, nil, nil, - nil, nil, nil, nil, 24, nil, nil, 49, nil, nil, - nil, nil, nil, nil, nil, nil, 26, 26, nil, nil, - nil, nil, nil, nil, nil, nil, 26, nil, nil, 25, - nil, 54, nil, nil, nil, nil, 49, nil, nil, nil, - nil, 26, nil, nil, nil, nil, nil, 25, 25, nil, - 25, nil, nil, nil, 54, 27, 27, nil, 27, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 26, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 25, nil, nil, 54, nil, 54, nil, 51, 27, nil, - nil, 25, nil, 49, 51, 51, nil, nil, nil, 27, - nil, nil, nil, 54, nil, 25, 49, nil, nil, nil, - 25, 25, nil, nil, nil, nil, nil, nil, 27, 27, - 25, nil, nil, 51, nil, nil, nil, 26, 27, nil, - nil, 54, nil, nil, nil, 25, nil, nil, nil, nil, - 26, nil, 51, 27, nil, 51, nil, nil, 51, nil, + 38, 22, 53, 33, 4, 71, 69, 2, 73, 86, + 63, 29, 36, 33, 39, 67, 32, 30, 83, 64, + 38, 22, 53, 61, 22, 23, 79, 5, 47, 47, + 24, 54, 48, 38, 43, 51, 75, 37, 31, 29, + 66, 3, 38, 22, 32, 30, 38, 22, 42, 75, + 37, 42, 6, 28, 69, 50, 5, 62, 29, 21, + 58, 6, 21, 32, 30, 6, 31, 70, 59, 72, + 57, 22, 23, 64, 36, 20, 8, 5, 3, 20, + 8, 28, 58, 50, 74, 31, 34, 76, 77, 78, + 35, 3, 71, 69, 58, 80, 81, 3, 82, 67, + 28, 41, 50, 55, 24, 84, 85, 37, 1, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 31, nil, + nil, nil, nil, 55, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 65, nil, nil, nil, 69, nil, + 42, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, 55, nil, 29, 29, nil, nil, 29, 32, + 30, nil, 39, 32, 30, 79, nil, 22, nil, nil, + nil, 22, 23, 26, 55, 3, nil, nil, nil, 54, + nil, 31, 31, 37, nil, 31, 55, nil, 38, 22, + 53, 86, 73, 36, 61, 69, 28, 28, 50, 50, + 28, 26, 50, 29, 25, 83, 71, 69, 54, 48, + nil, 5, 51, 54, 5, 37, 29, 38, 22, 53, + 26, 32, 30, nil, nil, nil, 37, 33, 29, nil, + 31, nil, 25, 32, 30, 55, nil, nil, 38, 22, + 53, 22, 29, 31, nil, 28, nil, 50, nil, 55, + nil, 25, nil, nil, nil, 31, nil, nil, 28, nil, + 50, 26, 4, nil, 26, nil, nil, nil, 27, 31, + 28, nil, 50, 65, 65, nil, nil, nil, 38, 22, + 53, nil, 29, 29, 28, nil, 50, 29, 30, 30, + nil, nil, 25, nil, nil, 25, 27, nil, nil, 65, + 31, nil, nil, 65, nil, 55, nil, 55, nil, 31, + 31, 38, 22, 53, 31, 27, 26, 26, 2, 63, + 26, nil, nil, nil, 28, 28, 50, 50, nil, 28, + nil, 50, nil, 55, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 29, nil, 4, 25, 25, nil, + nil, 25, nil, 26, nil, nil, 29, nil, nil, nil, + nil, 55, 38, 22, 53, 26, nil, nil, nil, nil, + nil, 31, 38, 22, 53, 38, 22, 53, 26, nil, + 55, 55, nil, 31, 25, nil, 28, nil, 50, nil, + 26, nil, 52, nil, 52, 52, 25, nil, 28, nil, + 50, nil, nil, 55, 26, nil, nil, nil, nil, 25, + nil, 27, 27, nil, nil, 27, nil, nil, 52, nil, + nil, 25, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 25, nil, 52, nil, nil, + 26, nil, 52, nil, 26, 26, 52, nil, nil, 26, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 54, nil, 54, nil, 25, nil, nil, nil, nil, nil, - nil, nil, 27, nil, nil, nil, nil, nil, nil, nil, + 27, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, 25, nil, 27, nil, 25, 25, nil, nil, nil, + 25, nil, nil, nil, nil, 27, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 27, + nil, nil, nil, nil, nil, nil, 26, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 26, 52, + 52, 52, nil, 52, 52, 52, 52, 52, 52, 52, + nil, 52, 52, 52, nil, nil, 52, 25, nil, 27, + 27, nil, nil, nil, 27, nil, nil, nil, nil, 25, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, 54, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 25, nil, nil, nil, nil, nil, nil, nil, 27, - nil, nil, nil, nil, 25, nil, nil, nil, nil, nil, - nil, nil, 27, nil, 51, 51, 51, nil, 51, 51, - 51, 51, 51, 51, 51, nil, 51, 51, 51, nil, - nil, 51, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 52, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 51 ] + nil, 27, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 27 ] racc_goto_pointer = [ - nil, 89, 10, 26, -13, 7, nil, -1, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, -7, - 48, 1, -1, -136, 116, 346, 252, 354, -15, -10, - -21, -11, 6, 19, -64, -33, -124, 0, -18, nil, - 57, -16, -153, nil, nil, nil, -189, -22, nil, 218, - -9, 528, 14, -25, 335, nil, -166, -12, -285, nil, - -54, -120, -23, -249, -13, -157, -173, nil, -147, -121, - -171, -203, -28, 38, 18, -80, 59, 23, 6, -78, - -39, -38, -113, -147, -18, -89, nil ] + nil, 108, 7, 41, -16, -161, 19, nil, 34, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + 33, 56, 1, 2, -136, 181, 150, 245, 30, -12, + -6, 15, -7, 2, 35, -50, -39, -105, 0, -38, + nil, 74, -63, -256, nil, nil, nil, -266, -19, nil, + 32, -16, 347, 2, -21, 74, nil, -164, -18, -263, + nil, -48, -107, -16, -261, 116, -175, -200, nil, -161, + -100, -162, -185, -24, 52, -1, -47, 70, 33, 8, + -63, -26, -24, -104, -120, 3, -94, nil ] racc_goto_default = [ - nil, nil, nil, 168, 25, 28, 32, 35, 5, 6, - 10, 13, 15, 18, 20, 24, 27, 31, 34, 4, - nil, 99, nil, 79, 101, 103, 105, 108, 109, 113, - 95, 96, 8, nil, nil, nil, nil, 85, nil, 30, - nil, nil, 161, 239, 164, 165, nil, nil, 144, 107, - 110, 111, 67, 134, 98, 150, 151, nil, 248, 104, - nil, nil, nil, nil, 69, nil, nil, 300, 80, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 57, - nil, nil, nil, nil, nil, nil, 192 ] + nil, nil, 278, 208, 25, nil, 31, 35, 4, 7, + 9, 14, 16, 19, 21, 24, 28, 30, 34, 3, + 6, nil, 98, nil, 76, 101, 102, 105, 107, 108, + 93, 94, 96, 12, nil, nil, nil, nil, 83, nil, + 33, nil, nil, 204, 290, 205, 206, nil, nil, 147, + 106, 109, 91, 64, 137, 97, 152, 153, nil, 259, + 104, nil, nil, nil, nil, 67, nil, nil, 301, 77, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + 58, nil, nil, nil, nil, nil, nil, 197 ] racc_token_table = { false => 0, @@ -1083,9 +1040,10 @@ Racc_token_to_s_table = [ 'IN', '$start', 'program', -'statements', +'statements_and_declarations', 'nil', -'statement', +'statement_or_declaration', +'statements', 'resource', 'virtualresource', 'collection', @@ -1175,48 +1133,39 @@ Racc_debug_parser = false # reduce 0 omitted -module_eval <<'.,.,', 'grammar.ra', 46 - def _reduce_1( val, _values, result ) - if val[0] - # Make sure we always return an array. - if val[0].is_a?(AST::ASTArray) - if val[0].children.empty? - result = nil - else - result = val[0] - end - else - result = aryfy(val[0]) - end - else - result = nil - end - result - end -.,., + # reduce 1 omitted # reduce 2 omitted - # reduce 3 omitted +module_eval <<'.,.,', 'grammar.ra', 36 + def _reduce_3( val, _values, result ) + result = ast AST::ASTArray, :children => (val[0] ? [val[0]] : []) + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 62 +module_eval <<'.,.,', 'grammar.ra', 42 def _reduce_4( val, _values, result ) - if val[0] and val[1] - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[1]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[1]] - end - elsif obj = (val[0] || val[1]) - result = obj - else result = nil + if val[1] + val[0].push(val[1]) end + result = val[0] result end .,., - # reduce 5 omitted +module_eval <<'.,.,', 'grammar.ra', 54 + def _reduce_5( val, _values, result ) + val[0].each do |stmt| + if stmt.is_a?(AST::TopLevelConstruct) + error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \ + :line => stmt.context[:line], :file => stmt.context[:file] + end + end + result = val[0] + result + end +.,., # reduce 6 omitted @@ -1244,22 +1193,22 @@ module_eval <<'.,.,', 'grammar.ra', 62 # reduce 18 omitted -module_eval <<'.,.,', 'grammar.ra', 82 - def _reduce_19( val, _values, result ) - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) + # reduce 19 omitted + +module_eval <<'.,.,', 'grammar.ra', 74 + def _reduce_20( val, _values, result ) + result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) result end .,., -module_eval <<'.,.,', 'grammar.ra', 85 - def _reduce_20( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 77 + def _reduce_21( val, _values, result ) result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) result end .,., - # reduce 21 omitted - # reduce 22 omitted # reduce 23 omitted @@ -1272,80 +1221,81 @@ module_eval <<'.,.,', 'grammar.ra', 85 # reduce 27 omitted -module_eval <<'.,.,', 'grammar.ra', 98 - def _reduce_28( val, _values, result ) - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement - result - end -.,., + # reduce 28 omitted -module_eval <<'.,.,', 'grammar.ra', 106 +module_eval <<'.,.,', 'grammar.ra', 89 def _reduce_29( val, _values, result ) - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => val[2], + :ftype => :statement result end .,., -module_eval <<'.,.,', 'grammar.ra', 112 +module_eval <<'.,.,', 'grammar.ra', 96 def _reduce_30( val, _values, result ) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :statement + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => val[2], + :ftype => :statement result end .,., -module_eval <<'.,.,', 'grammar.ra', 120 +module_eval <<'.,.,', 'grammar.ra', 102 def _reduce_31( val, _values, result ) - args = aryfy(val[1]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => AST::ASTArray.new({}), + :ftype => :statement result end .,., - # reduce 32 omitted +module_eval <<'.,.,', 'grammar.ra', 109 + def _reduce_32( val, _values, result ) + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => val[1], + :ftype => :statement + result + end +.,., - # reduce 33 omitted +module_eval <<'.,.,', 'grammar.ra', 110 + def _reduce_33( val, _values, result ) + result = aryfy(val[0]) + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 128 +module_eval <<'.,.,', 'grammar.ra', 111 def _reduce_34( val, _values, result ) - result = aryfy(val[0], val[2]) - result.line = @lexer.line - result.file = @lexer.file + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 137 +module_eval <<'.,.,', 'grammar.ra', 116 def _reduce_35( val, _values, result ) - unless val[0].is_a?(AST::ASTArray) - val[0] = aryfy(val[0]) - end - val[0].push(val[2]) - result = val[0] result end .,., - # reduce 36 omitted +module_eval <<'.,.,', 'grammar.ra', 120 + def _reduce_36( val, _values, result ) + val[0].push(val[2]) + result = val[0] + result + end +.,., # reduce 37 omitted @@ -1361,223 +1311,198 @@ module_eval <<'.,.,', 'grammar.ra', 137 # reduce 43 omitted -module_eval <<'.,.,', 'grammar.ra', 151 - def _reduce_44( val, _values, result ) - result = ast AST::Name, :value => val[0][:value] - result - end -.,., + # reduce 44 omitted -module_eval <<'.,.,', 'grammar.ra', 173 +module_eval <<'.,.,', 'grammar.ra', 134 def _reduce_45( val, _values, result ) - @lexer.commentpop - array = val[2] - if array.instance_of?(AST::ResourceInstance) - array = [array] - end - result = ast AST::ASTArray - - # this iterates across each specified resourceinstance - array.each { |instance| - unless instance.instance_of?(AST::ResourceInstance) - raise Puppet::Dev, "Got something that isn't an instance" - end - # now, i need to somehow differentiate between those things with - # arrays in their names, and normal things - result.push ast(AST::Resource, - :type => val[0], - :title => instance[0], - :parameters => instance[1]) - } + result = ast AST::Name, :value => val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 176 +module_eval <<'.,.,', 'grammar.ra', 139 def _reduce_46( val, _values, result ) - # This is a deprecated syntax. - error "All resource specifications require names" + @lexer.commentpop + result = ast(AST::Resource, :type => val[0], :instances => val[2]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 180 +module_eval <<'.,.,', 'grammar.ra', 142 def _reduce_47( val, _values, result ) - # a defaults setting for a type - @lexer.commentpop - result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) + # This is a deprecated syntax. + error "All resource specifications require names" result end .,., -module_eval <<'.,.,', 'grammar.ra', 186 +module_eval <<'.,.,', 'grammar.ra', 146 def _reduce_48( val, _values, result ) - @lexer.commentpop - result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] + # a defaults setting for a type + @lexer.commentpop + result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 213 +module_eval <<'.,.,', 'grammar.ra', 152 def _reduce_49( val, _values, result ) - type = val[0] + @lexer.commentpop + result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] + result + end +.,., - if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect without storeconfigs being set") - end +module_eval <<'.,.,', 'grammar.ra', 171 + def _reduce_50( val, _values, result ) + type = val[0] - if val[1].is_a? AST::ResourceDefaults - error "Defaults are not virtualizable" - end + if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect without storeconfigs being set") + end - method = type.to_s + "=" + error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults - # Just mark our resources as exported and pass them through. - if val[1].instance_of?(AST::ASTArray) - val[1].each do |obj| - obj.send(method, true) - end - else - val[1].send(method, true) - end + method = type.to_s + "=" - result = val[1] + # Just mark our resource as exported and pass it through. + val[1].send(method, true) + + result = val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 214 - def _reduce_50( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 172 + def _reduce_51( val, _values, result ) result = :virtual result end .,., -module_eval <<'.,.,', 'grammar.ra', 215 - def _reduce_51( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 173 + def _reduce_52( val, _values, result ) result = :exported result end .,., -module_eval <<'.,.,', 'grammar.ra', 240 - def _reduce_52( val, _values, result ) - @lexer.commentpop - if val[0] =~ /^[a-z]/ - Puppet.warning addcontext("Collection names must now be capitalized") - end - type = val[0].downcase - args = {:type => type} - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - args[:override] = val[3] - result = ast AST::Collection, args +module_eval <<'.,.,', 'grammar.ra', 196 + def _reduce_53( val, _values, result ) + @lexer.commentpop + Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/ + type = val[0].downcase + args = {:type => type} + + if val[1].is_a?(AST::CollExpr) + args[:query] = val[1] + args[:query].type = type + args[:form] = args[:query].form + else + args[:form] = val[1] + end + if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") + end + args[:override] = val[3] + result = ast AST::Collection, args result end .,., -module_eval <<'.,.,', 'grammar.ra', 259 - def _reduce_53( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 215 + def _reduce_54( val, _values, result ) if val[0] =~ /^[a-z]/ - Puppet.warning addcontext("Collection names must now be capitalized") - end - type = val[0].downcase - args = {:type => type } - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - result = ast AST::Collection, args + Puppet.warning addcontext("Collection names must now be capitalized") + end + type = val[0].downcase + args = {:type => type } + + if val[1].is_a?(AST::CollExpr) + args[:query] = val[1] + args[:query].type = type + args[:form] = args[:query].form + else + args[:form] = val[1] + end + if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") + end + result = ast AST::Collection, args result end .,., -module_eval <<'.,.,', 'grammar.ra', 269 - def _reduce_54( val, _values, result ) - if val[1] - result = val[1] - result.form = :virtual - else - result = :virtual - end +module_eval <<'.,.,', 'grammar.ra', 225 + def _reduce_55( val, _values, result ) + if val[1] + result = val[1] + result.form = :virtual + else + result = :virtual + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 277 - def _reduce_55( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 233 + def _reduce_56( val, _values, result ) if val[1] - result = val[1] - result.form = :exported - else - result = :exported - end + result = val[1] + result.form = :exported + else + result = :exported + end result end .,., - # reduce 56 omitted - # reduce 57 omitted -module_eval <<'.,.,', 'grammar.ra', 285 - def _reduce_58( val, _values, result ) + # reduce 58 omitted + +module_eval <<'.,.,', 'grammar.ra', 241 + def _reduce_59( val, _values, result ) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] result end .,., - # reduce 59 omitted + # reduce 60 omitted -module_eval <<'.,.,', 'grammar.ra', 291 - def _reduce_60( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 247 + def _reduce_61( val, _values, result ) result = val[1] result.parens = true result end .,., -module_eval <<'.,.,', 'grammar.ra', 292 - def _reduce_61( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 248 + def _reduce_62( val, _values, result ) result=val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 293 - def _reduce_62( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 249 + def _reduce_63( val, _values, result ) result=val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 300 - def _reduce_63( val, _values, result ) - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] - #result = ast AST::CollExpr - #result.push *val +module_eval <<'.,.,', 'grammar.ra', 256 + def _reduce_64( val, _values, result ) + result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] + #result = ast AST::CollExpr + #result.push *val result end .,., -module_eval <<'.,.,', 'grammar.ra', 305 - def _reduce_64( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 261 + def _reduce_65( val, _values, result ) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] #result = ast AST::CollExpr #result.push *val @@ -1585,57 +1510,56 @@ module_eval <<'.,.,', 'grammar.ra', 305 end .,., - # reduce 65 omitted - # reduce 66 omitted -module_eval <<'.,.,', 'grammar.ra', 312 - def _reduce_67( val, _values, result ) - result = ast AST::ResourceInstance, :children => [val[0],val[2]] + # reduce 67 omitted + +module_eval <<'.,.,', 'grammar.ra', 268 + def _reduce_68( val, _values, result ) + result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] result end .,., - # reduce 68 omitted - -module_eval <<'.,.,', 'grammar.ra', 322 +module_eval <<'.,.,', 'grammar.ra', 269 def _reduce_69( val, _values, result ) - if val[0].instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray, :children => [val[0],val[2]] - else - val[0].push val[2] - result = val[0] - end + result = aryfy(val[0]) result end .,., - # reduce 70 omitted - - # reduce 71 omitted - -module_eval <<'.,.,', 'grammar.ra', 329 - def _reduce_72( val, _values, result ) - result = ast AST::Undef, :value => :undef +module_eval <<'.,.,', 'grammar.ra', 274 + def _reduce_70( val, _values, result ) + val[0].push val[2] + result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 333 + # reduce 71 omitted + + # reduce 72 omitted + +module_eval <<'.,.,', 'grammar.ra', 281 def _reduce_73( val, _values, result ) - result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Undef, :value => :undef result end .,., -module_eval <<'.,.,', 'grammar.ra', 337 +module_eval <<'.,.,', 'grammar.ra', 285 def _reduce_74( val, _values, result ) - result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] result end .,., - # reduce 75 omitted +module_eval <<'.,.,', 'grammar.ra', 289 + def _reduce_75( val, _values, result ) + result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] + result + end +.,., # reduce 76 omitted @@ -1649,118 +1573,109 @@ module_eval <<'.,.,', 'grammar.ra', 337 # reduce 81 omitted -module_eval <<'.,.,', 'grammar.ra', 354 - def _reduce_82( val, _values, result ) - if val[0][:value] =~ /::/ - raise Puppet::ParseError, "Cannot assign to variables in other namespaces" - end - # this is distinct from referencing a variable - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] - result - end -.,., + # reduce 82 omitted -module_eval <<'.,.,', 'grammar.ra', 357 +module_eval <<'.,.,', 'grammar.ra', 304 def _reduce_83( val, _values, result ) - result = ast AST::VarDef, :name => val[0], :value => val[2] + raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ + # this is distinct from referencing a variable + variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 362 +module_eval <<'.,.,', 'grammar.ra', 307 def _reduce_84( val, _values, result ) - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] + result = ast AST::VarDef, :name => val[0], :value => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 367 +module_eval <<'.,.,', 'grammar.ra', 312 def _reduce_85( val, _values, result ) - result = ast AST::ASTArray + variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 367 +module_eval <<'.,.,', 'grammar.ra', 317 def _reduce_86( val, _values, result ) - result = val[0] + result = ast AST::ASTArray result end .,., -module_eval <<'.,.,', 'grammar.ra', 376 +module_eval <<'.,.,', 'grammar.ra', 317 def _reduce_87( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 380 +module_eval <<'.,.,', 'grammar.ra', 322 def _reduce_88( val, _values, result ) - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] + val[0].push(val[2]) + result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 385 +module_eval <<'.,.,', 'grammar.ra', 326 def _reduce_89( val, _values, result ) - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], - :add => true + result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] result end .,., - # reduce 90 omitted - - # reduce 91 omitted - -module_eval <<'.,.,', 'grammar.ra', 393 - def _reduce_92( val, _values, result ) - result = ast AST::ASTArray +module_eval <<'.,.,', 'grammar.ra', 331 + def _reduce_90( val, _values, result ) + result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], + :add => true result end .,., -module_eval <<'.,.,', 'grammar.ra', 393 + # reduce 91 omitted + + # reduce 92 omitted + +module_eval <<'.,.,', 'grammar.ra', 339 def _reduce_93( val, _values, result ) - result = val[0] + result = ast AST::ASTArray result end .,., -module_eval <<'.,.,', 'grammar.ra', 402 +module_eval <<'.,.,', 'grammar.ra', 339 def _reduce_94( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., - # reduce 95 omitted +module_eval <<'.,.,', 'grammar.ra', 344 + def _reduce_95( val, _values, result ) + val[0].push(val[2]) + result = val[0] + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 411 +module_eval <<'.,.,', 'grammar.ra', 345 def _reduce_96( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - result = val[0].push(val[2]) - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., - # reduce 97 omitted +module_eval <<'.,.,', 'grammar.ra', 346 + def _reduce_97( val, _values, result ) + result = val[0].push(val[2]) + result + end +.,., # reduce 98 omitted @@ -1796,392 +1711,387 @@ module_eval <<'.,.,', 'grammar.ra', 411 # reduce 114 omitted -module_eval <<'.,.,', 'grammar.ra', 440 - def _reduce_115( val, _values, result ) - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => args, - :ftype => :rvalue - result - end -.,., + # reduce 115 omitted -module_eval <<'.,.,', 'grammar.ra', 445 +module_eval <<'.,.,', 'grammar.ra', 375 def _reduce_116( val, _values, result ) - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :rvalue + result = ast AST::Function, + :name => val[0][:value], :line => val[0][:line], + :arguments => val[2], + :ftype => :rvalue result end .,., -module_eval <<'.,.,', 'grammar.ra', 446 +module_eval <<'.,.,', 'grammar.ra', 380 def _reduce_117( val, _values, result ) - result = ast AST::String, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Function, + :name => val[0][:value], :line => val[0][:line], + :arguments => AST::ASTArray.new({}), + :ftype => :rvalue result end .,., -module_eval <<'.,.,', 'grammar.ra', 447 +module_eval <<'.,.,', 'grammar.ra', 381 def _reduce_118( val, _values, result ) - result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] + result = ast AST::String, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 449 +module_eval <<'.,.,', 'grammar.ra', 382 def _reduce_119( val, _values, result ) - result = [val[0]] + val[1] + result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 451 +module_eval <<'.,.,', 'grammar.ra', 384 def _reduce_120( val, _values, result ) - result = [ast(AST::String,val[0])] + result = [val[0]] + val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 452 +module_eval <<'.,.,', 'grammar.ra', 386 def _reduce_121( val, _values, result ) - result = [ast(AST::String,val[0])] + val[1] + result = [ast(AST::String,val[0])] result end .,., -module_eval <<'.,.,', 'grammar.ra', 457 +module_eval <<'.,.,', 'grammar.ra', 387 def _reduce_122( val, _values, result ) - result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] + result = [ast(AST::String,val[0])] + val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 462 +module_eval <<'.,.,', 'grammar.ra', 392 def _reduce_123( val, _values, result ) - Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") - result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] + result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 464 +module_eval <<'.,.,', 'grammar.ra', 397 def _reduce_124( val, _values, result ) - result = ast AST::ResourceReference, :type => val[0], :title => val[2] + Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") + result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 468 +module_eval <<'.,.,', 'grammar.ra', 399 def _reduce_125( val, _values, result ) - result = val[1] + result = ast AST::ResourceReference, :type => val[0], :title => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 482 +module_eval <<'.,.,', 'grammar.ra', 403 def _reduce_126( val, _values, result ) - @lexer.commentpop - args = { - :test => val[0], - :statements => val[2] - } + result = val[1] + result + end +.,., - if val[4] - args[:else] = val[4] - end +module_eval <<'.,.,', 'grammar.ra', 415 + def _reduce_127( val, _values, result ) + @lexer.commentpop + args = { + :test => val[0], + :statements => val[2] + } + + args[:else] = val[4] if val[4] - result = ast AST::IfStatement, args + result = ast AST::IfStatement, args result end .,., -module_eval <<'.,.,', 'grammar.ra', 495 - def _reduce_127( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 426 + def _reduce_128( val, _values, result ) @lexer.commentpop args = { - :test => val[0], - :statements => ast(AST::Nop) - } + :test => val[0], + :statements => ast(AST::Nop) + } - if val[3] - args[:else] = val[3] - end + args[:else] = val[3] if val[3] - result = ast AST::IfStatement, args + result = ast AST::IfStatement, args result end .,., - # reduce 128 omitted + # reduce 129 omitted -module_eval <<'.,.,', 'grammar.ra', 501 - def _reduce_129( val, _values, result ) - #@lexer.commentpop +module_eval <<'.,.,', 'grammar.ra', 431 + def _reduce_130( val, _values, result ) result = ast AST::Else, :statements => val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 505 - def _reduce_130( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 435 + def _reduce_131( val, _values, result ) @lexer.commentpop result = ast AST::Else, :statements => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 509 - def _reduce_131( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 439 + def _reduce_132( val, _values, result ) @lexer.commentpop result = ast AST::Else, :statements => ast(AST::Nop) result end .,., - # reduce 132 omitted + # reduce 133 omitted -module_eval <<'.,.,', 'grammar.ra', 526 - def _reduce_133( val, _values, result ) - result = ast AST::InOperator, :lval => val[0], :rval => val[2] - result - end -.,., - -module_eval <<'.,.,', 'grammar.ra', 529 +module_eval <<'.,.,', 'grammar.ra', 456 def _reduce_134( val, _values, result ) - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::InOperator, :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 532 +module_eval <<'.,.,', 'grammar.ra', 459 def _reduce_135( val, _values, result ) result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 535 +module_eval <<'.,.,', 'grammar.ra', 462 def _reduce_136( val, _values, result ) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 538 +module_eval <<'.,.,', 'grammar.ra', 465 def _reduce_137( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 541 +module_eval <<'.,.,', 'grammar.ra', 468 def _reduce_138( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 544 +module_eval <<'.,.,', 'grammar.ra', 471 def _reduce_139( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 547 +module_eval <<'.,.,', 'grammar.ra', 474 def _reduce_140( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 550 +module_eval <<'.,.,', 'grammar.ra', 477 def _reduce_141( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 553 +module_eval <<'.,.,', 'grammar.ra', 480 def _reduce_142( val, _values, result ) - result = ast AST::Minus, :value => val[1] + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 556 +module_eval <<'.,.,', 'grammar.ra', 483 def _reduce_143( val, _values, result ) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::Minus, :value => val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 559 +module_eval <<'.,.,', 'grammar.ra', 486 def _reduce_144( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 562 +module_eval <<'.,.,', 'grammar.ra', 489 def _reduce_145( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 565 +module_eval <<'.,.,', 'grammar.ra', 492 def _reduce_146( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 568 +module_eval <<'.,.,', 'grammar.ra', 495 def _reduce_147( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 571 +module_eval <<'.,.,', 'grammar.ra', 498 def _reduce_148( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 574 +module_eval <<'.,.,', 'grammar.ra', 501 def _reduce_149( val, _values, result ) - result = ast AST::Not, :value => val[1] + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 577 +module_eval <<'.,.,', 'grammar.ra', 504 def _reduce_150( val, _values, result ) - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::Not, :value => val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 580 +module_eval <<'.,.,', 'grammar.ra', 507 def _reduce_151( val, _values, result ) result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 583 +module_eval <<'.,.,', 'grammar.ra', 510 def _reduce_152( val, _values, result ) - result = val[1] + result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 592 +module_eval <<'.,.,', 'grammar.ra', 513 def _reduce_153( val, _values, result ) - @lexer.commentpop - options = val[3] - unless options.instance_of?(AST::ASTArray) - options = ast AST::ASTArray, :children => [val[3]] - end - result = ast AST::CaseStatement, :test => val[1], :options => options + result = val[1] result end .,., - # reduce 154 omitted +module_eval <<'.,.,', 'grammar.ra', 518 + def _reduce_154( val, _values, result ) + @lexer.commentpop + result = ast AST::CaseStatement, :test => val[1], :options => val[3] + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 602 +module_eval <<'.,.,', 'grammar.ra', 519 def _reduce_155( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push val[1] - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0], val[1]] - end + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 607 +module_eval <<'.,.,', 'grammar.ra', 524 def _reduce_156( val, _values, result ) - @lexer.commentpop - result = ast AST::CaseOpt, :value => val[0], :statements => val[3] + val[0].push val[1] + result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 613 +module_eval <<'.,.,', 'grammar.ra', 529 def _reduce_157( val, _values, result ) - @lexer.commentpop - result = ast(AST::CaseOpt, - :value => val[0], - :statements => ast(AST::ASTArray) - ) + @lexer.commentpop + result = ast AST::CaseOpt, :value => val[0], :statements => val[3] result end .,., - # reduce 158 omitted +module_eval <<'.,.,', 'grammar.ra', 538 + def _reduce_158( val, _values, result ) + @lexer.commentpop -module_eval <<'.,.,', 'grammar.ra', 623 + result = ast( + AST::CaseOpt, + :value => val[0], + + :statements => ast(AST::ASTArray) + ) + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 539 def _reduce_159( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 627 +module_eval <<'.,.,', 'grammar.ra', 544 def _reduce_160( val, _values, result ) - result = ast AST::Selector, :param => val[0], :values => val[2] + val[0].push(val[2]) + result = val[0] result end .,., - # reduce 161 omitted +module_eval <<'.,.,', 'grammar.ra', 548 + def _reduce_161( val, _values, result ) + result = ast AST::Selector, :param => val[0], :values => val[2] + result + end +.,., + + # reduce 162 omitted -module_eval <<'.,.,', 'grammar.ra', 633 - def _reduce_162( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 554 + def _reduce_163( val, _values, result ) @lexer.commentpop result = val[1] result end .,., - # reduce 163 omitted + # reduce 164 omitted -module_eval <<'.,.,', 'grammar.ra', 643 - def _reduce_164( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 564 + def _reduce_165( val, _values, result ) if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + val[0].push(val[2]) + result = val[0] + else + result = ast AST::ASTArray, :children => [val[0],val[2]] + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 647 - def _reduce_165( val, _values, result ) - result = ast AST::ResourceParam, :param => val[0], :value => val[2] +module_eval <<'.,.,', 'grammar.ra', 568 + def _reduce_166( val, _values, result ) + result = ast AST::ResourceParam, :param => val[0], :value => val[2] result end .,., - # reduce 166 omitted - # reduce 167 omitted # reduce 168 omitted @@ -2194,208 +2104,217 @@ module_eval <<'.,.,', 'grammar.ra', 647 # reduce 172 omitted -module_eval <<'.,.,', 'grammar.ra', 658 - def _reduce_173( val, _values, result ) + # reduce 173 omitted + +module_eval <<'.,.,', 'grammar.ra', 579 + def _reduce_174( val, _values, result ) result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] result end .,., - # reduce 174 omitted + # reduce 175 omitted -module_eval <<'.,.,', 'grammar.ra', 661 - def _reduce_175( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 582 + def _reduce_176( val, _values, result ) result = [val[0][:value]] result end .,., - # reduce 176 omitted + # reduce 177 omitted -module_eval <<'.,.,', 'grammar.ra', 663 - def _reduce_177( val, _values, result ) - result = val[0] += val[2] - result - end -.,., - -module_eval <<'.,.,', 'grammar.ra', 672 +module_eval <<'.,.,', 'grammar.ra', 584 def _reduce_178( val, _values, result ) - val[1].each do |file| - import(file) - end - - result = AST::ASTArray.new(:children => []) + result = val[0] += val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 683 +module_eval <<'.,.,', 'grammar.ra', 593 def _reduce_179( val, _values, result ) - @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line] - @lexer.indefine = false - result = nil + val[1].each do |file| + import(file) + end -#} | DEFINE NAME argumentlist parent LBRACE RBRACE { + result = nil result end .,., -module_eval <<'.,.,', 'grammar.ra', 688 +module_eval <<'.,.,', 'grammar.ra', 605 def _reduce_180( val, _values, result ) - @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line] - @lexer.indefine = false - result = nil + @lexer.commentpop + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :code => val[4], + :line => val[0][:line])) + @lexer.indefine = false + +#} | DEFINE NAME argumentlist parent LBRACE RBRACE { result end .,., -module_eval <<'.,.,', 'grammar.ra', 697 +module_eval <<'.,.,', 'grammar.ra', 610 def _reduce_181( val, _values, result ) - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line] - result = nil + @lexer.commentpop + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) + @lexer.indefine = false result end .,., -module_eval <<'.,.,', 'grammar.ra', 703 +module_eval <<'.,.,', 'grammar.ra', 620 def _reduce_182( val, _values, result ) - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line] - result = nil + @lexer.commentpop + # Our class gets defined in the parent namespace, not our own. + @lexer.namepop + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :code => val[5], :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 709 +module_eval <<'.,.,', 'grammar.ra', 627 def _reduce_183( val, _values, result ) - @lexer.commentpop - newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line] - result = nil + @lexer.commentpop + # Our class gets defined in the parent namespace, not our own. + @lexer.namepop + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 713 +module_eval <<'.,.,', 'grammar.ra', 634 def _reduce_184( val, _values, result ) - @lexer.commentpop - newnode val[1], :parent => val[2], :line => val[0][:line] - result = nil + @lexer.commentpop + result = Puppet::Parser::AST::Node.new(val[1], + ast_context(true).merge(:parent => val[2], :code => val[4], + :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 714 +module_eval <<'.,.,', 'grammar.ra', 637 def _reduce_185( val, _values, result ) - result = val[0][:value] + @lexer.commentpop + result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 716 +module_eval <<'.,.,', 'grammar.ra', 638 def _reduce_186( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 717 +module_eval <<'.,.,', 'grammar.ra', 640 def _reduce_187( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 718 +module_eval <<'.,.,', 'grammar.ra', 641 def _reduce_188( val, _values, result ) - result = "class" + result = val[0][:value] result end .,., - # reduce 189 omitted +module_eval <<'.,.,', 'grammar.ra', 642 + def _reduce_189( val, _values, result ) + result = "class" + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 728 +module_eval <<'.,.,', 'grammar.ra', 649 def _reduce_190( val, _values, result ) - result = val[0] - result = [result] unless result.is_a?(Array) - result << val[2] + result = [result] result end .,., -module_eval <<'.,.,', 'grammar.ra', 732 +module_eval <<'.,.,', 'grammar.ra', 653 def _reduce_191( val, _values, result ) - result = ast AST::HostName, :value => val[0] + result = val[0] + result << val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 733 +module_eval <<'.,.,', 'grammar.ra', 657 def _reduce_192( val, _values, result ) - result = val[0][:value] + result = ast AST::HostName, :value => val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 734 +module_eval <<'.,.,', 'grammar.ra', 658 def _reduce_193( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 735 +module_eval <<'.,.,', 'grammar.ra', 659 def _reduce_194( val, _values, result ) result = val[0][:value] result end .,., - # reduce 195 omitted - -module_eval <<'.,.,', 'grammar.ra', 741 - def _reduce_196( val, _values, result ) - result = nil +module_eval <<'.,.,', 'grammar.ra', 660 + def _reduce_195( val, _values, result ) + result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 745 + # reduce 196 omitted + +module_eval <<'.,.,', 'grammar.ra', 666 def _reduce_197( val, _values, result ) - result = ast AST::ASTArray, :children => [] + result = nil + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 670 + def _reduce_198( val, _values, result ) + result = ast AST::ASTArray, :children => [] result end .,., - # reduce 198 omitted + # reduce 199 omitted -module_eval <<'.,.,', 'grammar.ra', 750 - def _reduce_199( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 675 + def _reduce_200( val, _values, result ) result = nil result end .,., -module_eval <<'.,.,', 'grammar.ra', 754 - def _reduce_200( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 679 + def _reduce_201( val, _values, result ) result = val[1] result = [result] unless result[0].is_a?(Array) result end .,., - # reduce 201 omitted + # reduce 202 omitted -module_eval <<'.,.,', 'grammar.ra', 761 - def _reduce_202( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 686 + def _reduce_203( val, _values, result ) result = val[0] result = [result] unless result[0].is_a?(Array) result << val[2] @@ -2403,189 +2322,181 @@ module_eval <<'.,.,', 'grammar.ra', 761 end .,., -module_eval <<'.,.,', 'grammar.ra', 766 - def _reduce_203( val, _values, result ) - Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") - result = [val[0][:value], val[2]] +module_eval <<'.,.,', 'grammar.ra', 691 + def _reduce_204( val, _values, result ) + Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") + result = [val[0][:value], val[2]] result end .,., -module_eval <<'.,.,', 'grammar.ra', 770 - def _reduce_204( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 695 + def _reduce_205( val, _values, result ) Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0][:value]] result end .,., -module_eval <<'.,.,', 'grammar.ra', 772 - def _reduce_205( val, _values, result ) - result = [val[0][:value], val[2]] +module_eval <<'.,.,', 'grammar.ra', 697 + def _reduce_206( val, _values, result ) + result = [val[0][:value], val[2]] result end .,., -module_eval <<'.,.,', 'grammar.ra', 774 - def _reduce_206( val, _values, result ) - result = [val[0][:value]] +module_eval <<'.,.,', 'grammar.ra', 699 + def _reduce_207( val, _values, result ) + result = [val[0][:value]] result end .,., - # reduce 207 omitted + # reduce 208 omitted -module_eval <<'.,.,', 'grammar.ra', 779 - def _reduce_208( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 704 + def _reduce_209( val, _values, result ) result = val[1] result end .,., - # reduce 209 omitted + # reduce 210 omitted -module_eval <<'.,.,', 'grammar.ra', 784 - def _reduce_210( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 709 + def _reduce_211( val, _values, result ) result = val[1] result end .,., - # reduce 211 omitted - # reduce 212 omitted -module_eval <<'.,.,', 'grammar.ra', 790 - def _reduce_213( val, _values, result ) - result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] - result - end -.,., + # reduce 213 omitted -module_eval <<'.,.,', 'grammar.ra', 798 +module_eval <<'.,.,', 'grammar.ra', 715 def _reduce_214( val, _values, result ) - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end + result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 805 +module_eval <<'.,.,', 'grammar.ra', 716 def _reduce_215( val, _values, result ) - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end + result = val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 807 +module_eval <<'.,.,', 'grammar.ra', 717 def _reduce_216( val, _values, result ) - result = ast AST::ASTArray + result = val[1] result end .,., - # reduce 217 omitted +module_eval <<'.,.,', 'grammar.ra', 718 + def _reduce_217( val, _values, result ) + result = ast AST::ASTArray + result + end +.,., # reduce 218 omitted # reduce 219 omitted -module_eval <<'.,.,', 'grammar.ra', 812 - def _reduce_220( val, _values, result ) + # reduce 220 omitted + +module_eval <<'.,.,', 'grammar.ra', 724 + def _reduce_221( val, _values, result ) result = nil result end .,., -module_eval <<'.,.,', 'grammar.ra', 817 - def _reduce_221( val, _values, result ) - result = ast AST::Regex, :value => val[0][:value] +module_eval <<'.,.,', 'grammar.ra', 729 + def _reduce_222( val, _values, result ) + result = ast AST::Regex, :value => val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 825 - def _reduce_222( val, _values, result ) - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end +module_eval <<'.,.,', 'grammar.ra', 737 + def _reduce_223( val, _values, result ) + if val[1].instance_of?(AST::ASTHash) + result = val[1] + else + result = ast AST::ASTHash, { :value => val[1] } + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 832 - def _reduce_223( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 744 + def _reduce_224( val, _values, result ) if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end + result = val[1] + else + result = ast AST::ASTHash, { :value => val[1] } + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 834 - def _reduce_224( val, _values, result ) - result = ast AST::ASTHash +module_eval <<'.,.,', 'grammar.ra', 746 + def _reduce_225( val, _values, result ) + result = ast AST::ASTHash result end .,., - # reduce 225 omitted + # reduce 226 omitted -module_eval <<'.,.,', 'grammar.ra', 844 - def _reduce_226( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 756 + def _reduce_227( val, _values, result ) if val[0].instance_of?(AST::ASTHash) - result = val[0].merge(val[2]) - else - result = ast AST::ASTHash, :value => val[0] - result.merge(val[2]) - end + result = val[0].merge(val[2]) + else + result = ast AST::ASTHash, :value => val[0] + result.merge(val[2]) + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 848 - def _reduce_227( val, _values, result ) - result = ast AST::ASTHash, { :value => { val[0] => val[2] } } +module_eval <<'.,.,', 'grammar.ra', 760 + def _reduce_228( val, _values, result ) + result = ast AST::ASTHash, { :value => { val[0] => val[2] } } result end .,., -module_eval <<'.,.,', 'grammar.ra', 849 - def _reduce_228( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 761 + def _reduce_229( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 850 - def _reduce_229( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 762 + def _reduce_230( val, _values, result ) result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 855 - def _reduce_230( val, _values, result ) - result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] +module_eval <<'.,.,', 'grammar.ra', 767 + def _reduce_231( val, _values, result ) + result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] result end .,., - # reduce 231 omitted + # reduce 232 omitted -module_eval <<'.,.,', 'grammar.ra', 860 - def _reduce_232( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 772 + def _reduce_233( val, _values, result ) result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] result end diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index c0fd37178..746aa0f90 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -29,29 +29,20 @@ class Puppet::Parser::Parser message end - # Create an AST array out of all of the args - def aryfy(*args) - if args[0].instance_of?(AST::ASTArray) - result = args.shift - args.each { |arg| - result.push arg - } - else - result = ast AST::ASTArray, :children => args - end - - result + # Create an AST array containing a single element + def aryfy(arg) + ast AST::ASTArray, :children => [arg] end # Create an AST object, and automatically add the file and line information if # available. def ast(klass, hash = {}) - klass.new ast_context(klass.use_docs).merge(hash) + klass.new ast_context(klass.use_docs, hash[:line]).merge(hash) end - def ast_context(include_docs = false) + def ast_context(include_docs = false, ast_line = nil) result = { - :line => lexer.line, + :line => ast_line || lexer.line, :file => lexer.file } result[:doc] = lexer.getcomment(result[:line]) if include_docs @@ -68,13 +59,13 @@ class Puppet::Parser::Parser end # Raise a Parse error. - def error(message) + def error(message, options = {}) if brace = @lexer.expected message += "; expected '%s'" end except = Puppet::ParseError.new(message) - except.line = @lexer.line - except.file = @lexer.file if @lexer.file + except.line = options[:line] || @lexer.line + except.file = options[:file] || @lexer.file raise except end @@ -103,15 +94,15 @@ class Puppet::Parser::Parser end def find_hostclass(namespace, name) - known_resource_types.find_or_load(namespace, name, :hostclass) + known_resource_types.find_hostclass(namespace, name) end def find_definition(namespace, name) - known_resource_types.find_or_load(namespace, name, :definition) + known_resource_types.find_definition(namespace, name) end def import(file) - known_resource_types.loader.import_if_possible(file, @lexer.file) + known_resource_types.loader.import(file, @lexer.file) end def initialize(env) @@ -133,26 +124,6 @@ class Puppet::Parser::Parser return ns, n end - # Create a new class, or merge with an existing class. - def newclass(name, options = {}) - known_resource_types.add Puppet::Resource::Type.new(:hostclass, name, ast_context(true).merge(options)) - end - - # Create a new definition. - def newdefine(name, options = {}) - known_resource_types.add Puppet::Resource::Type.new(:definition, name, ast_context(true).merge(options)) - end - - # Create a new node. Nodes are special, because they're stored in a global - # table, not according to namespaces. - def newnode(names, options = {}) - names = [names] unless names.instance_of?(Array) - context = ast_context(true) - names.collect do |name| - known_resource_types.add(Puppet::Resource::Type.new(:node, name, context.merge(options))) - end - end - def on_error(token,value,stack) if token == 0 # denotes end of file value = 'end of file' @@ -174,48 +145,54 @@ class Puppet::Parser::Parser # how should I do error handling here? def parse(string = nil) - return parse_ruby_file if self.file =~ /\.rb$/ - self.string = string if string - begin - @yydebug = false - main = yyparse(@lexer,:scan) - rescue Racc::ParseError => except - error = Puppet::ParseError.new(except) - error.line = @lexer.line - error.file = @lexer.file - error.set_backtrace except.backtrace - raise error - rescue Puppet::ParseError => except - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue Puppet::Error => except - # and this is a framework error - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue Puppet::DevError => except - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue => except - error = Puppet::DevError.new(except.message) - error.line = @lexer.line - error.file = @lexer.file - error.set_backtrace except.backtrace - raise error - end - if main - # Store the results as the top-level class. - newclass("", :code => main) + if self.file =~ /\.rb$/ + main = parse_ruby_file + else + self.string = string if string + begin + @yydebug = false + main = yyparse(@lexer,:scan) + rescue Racc::ParseError => except + error = Puppet::ParseError.new(except) + error.line = @lexer.line + error.file = @lexer.file + error.set_backtrace except.backtrace + raise error + rescue Puppet::ParseError => except + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue Puppet::Error => except + # and this is a framework error + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue Puppet::DevError => except + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue => except + error = Puppet::DevError.new(except.message) + error.line = @lexer.line + error.file = @lexer.file + error.set_backtrace except.backtrace + raise error + end end - return known_resource_types + # Store the results as the top-level class. + return Puppet::Parser::AST::Hostclass.new('', :code => main) ensure @lexer.clear end def parse_ruby_file - require self.file + # Execute the contents of the file inside its own "main" object so + # that it can call methods in the resource type API. + main_object = Puppet::DSL::ResourceTypeAPI.new + main_object.instance_eval(File.read(self.file)) + + # Then extract any types that were created. + Puppet::Parser::AST::ASTArray.new :children => main_object.instance_eval { @__created_ast_objects__ } end def string=(string) diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index c956a1106..c007d4dbe 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -64,6 +64,8 @@ class Puppet::Parser::Resource < Puppet::Resource # Retrieve the associated definition and evaluate it. def evaluate + return if evaluated? + @evaluated = true if klass = resource_type and ! builtin_type? finish return klass.evaluate_code(self) @@ -72,8 +74,6 @@ class Puppet::Parser::Resource < Puppet::Resource else self.fail "Cannot find definition #{type}" end - ensure - @evaluated = true end # Mark this resource as both exported and virtual, @@ -94,6 +94,7 @@ class Puppet::Parser::Resource < Puppet::Resource @finished = true add_defaults add_metaparams + add_scope_tags validate end @@ -103,9 +104,9 @@ class Puppet::Parser::Resource < Puppet::Resource end def initialize(*args) + raise ArgumentError, "Resources require a scope" unless args.last[:scope] super - raise ArgumentError, "Resources require a scope" unless scope @source ||= scope.source end @@ -141,10 +142,6 @@ class Puppet::Parser::Resource < Puppet::Resource self[:name] || self.title end - def namespaces - scope.namespaces - end - # A temporary occasion, until I get paths in the scopes figured out. def path to_s @@ -264,6 +261,12 @@ class Puppet::Parser::Resource < Puppet::Resource end end + def add_scope_tags + if scope_resource = scope.resource + tag(*scope_resource.tags) + end + end + # Accept a parameter from an override. def override_parameter(param) # This can happen if the override is defining a new parameter, rather diff --git a/lib/puppet/parser/resource/param.rb b/lib/puppet/parser/resource/param.rb index af2d98fe8..c28322337 100644 --- a/lib/puppet/parser/resource/param.rb +++ b/lib/puppet/parser/resource/param.rb @@ -13,7 +13,7 @@ class Puppet::Parser::Resource::Param def initialize(hash) set_options(hash) - requiredopts(:name, :value, :source) + requiredopts(:name, :value) @name = symbolize(@name) end diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index ae0f9ea4a..24f1d01f7 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -474,6 +474,41 @@ class Puppet::Parser::Scope end end + def find_resource_type(type) + # It still works fine without the type == 'class' short-cut, but it is a lot slower. + return nil if ["class", "node"].include? type.to_s.downcase + find_builtin_resource_type(type) || find_defined_resource_type(type) + end + + def find_builtin_resource_type(type) + Puppet::Type.type(type.to_s.downcase.to_sym) + end + + def find_defined_resource_type(type) + environment.known_resource_types.find_definition(namespaces, type.to_s.downcase) + end + + def resolve_type_and_titles(type, titles) + raise ArgumentError, "titles must be an array" unless titles.is_a?(Array) + + case type.downcase + when "class" + # resolve the titles + titles = titles.collect do |a_title| + hostclass = find_hostclass(a_title) + hostclass ? hostclass.name : a_title + end + when "node" + # no-op + else + # resolve the type + resource_type = find_resource_type(type) + type = resource_type.name if resource_type + end + + return [type, titles] + end + private def extend_with_functions_module diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 73a4ad8aa..6864aa1a9 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -1,6 +1,7 @@ # A simple wrapper for templates, so they don't have full access to # the scope objects. require 'puppet/parser/files' +require 'erb' class Puppet::Parser::TemplateWrapper attr_writer :scope diff --git a/lib/puppet/parser/type_loader.rb b/lib/puppet/parser/type_loader.rb index 35ad49593..140c9f2ca 100644 --- a/lib/puppet/parser/type_loader.rb +++ b/lib/puppet/parser/type_loader.rb @@ -3,25 +3,56 @@ require 'puppet/node/environment' class Puppet::Parser::TypeLoader include Puppet::Node::Environment::Helper - class Helper < Hash + # Helper class that makes sure we don't try to import the same file + # more than once from either the same thread or different threads. + class Helper include MonitorMixin - def done_with(item) - synchronize do - delete(item)[:busy].signal if self.has_key?(item) and self[item][:loader] == Thread.current - end + def initialize + super + # These hashes are indexed by filename + @state = {} # :doing or :done + @thread = {} # if :doing, thread that's doing the parsing + @cond_var = {} # if :doing, condition var that will be signaled when done. end - def owner_of(item) - synchronize do - if !self.has_key? item - self[item] = { :loader => Thread.current, :busy => self.new_cond} - :nobody - elsif self[item][:loader] == Thread.current - :this_thread + + # Execute the supplied block exactly once per file, no matter how + # many threads have asked for it to run. If another thread is + # already executing it, wait for it to finish. If this thread is + # already executing it, return immediately without executing the + # block. + # + # Note: the reason for returning immediately if this thread is + # already executing the block is to handle the case of a circular + # import--when this happens, we attempt to recursively re-parse a + # file that we are already in the process of parsing. To prevent + # an infinite regress we need to simply do nothing when the + # recursive import is attempted. + def do_once(file) + need_to_execute = synchronize do + case @state[file] + when :doing + if @thread[file] != Thread.current + @cond_var[file].wait + end + false + when :done + false else - flag = self[item][:busy] - flag.wait - flag.signal - :another_thread + @state[file] = :doing + @thread[file] = Thread.current + @cond_var[file] = new_cond + true + end + end + if need_to_execute + begin + yield + ensure + synchronize do + @state[file] = :done + @thread.delete(file) + @cond_var.delete(file).broadcast + end end end end @@ -47,21 +78,18 @@ class Puppet::Parser::TypeLoader raise Puppet::ImportError.new("No file(s) found for import of '#{pat}'") end + loaded_asts = [] files.each do |file| unless file =~ /^#{File::SEPARATOR}/ file = File.join(dir, file) end - unless imported? file - @imported[file] = true - parse_file(file) + @loading_helper.do_once(file) do + loaded_asts << parse_file(file) end end - - modname - end - - def imported?(file) - @imported.has_key?(file) + loaded_asts.inject([]) do |loaded_types, ast| + loaded_types + known_resource_types.import_ast(ast, modname) + end end def known_resource_types @@ -70,77 +98,48 @@ class Puppet::Parser::TypeLoader def initialize(env) self.environment = env - @loaded = {} - @loading = Helper.new - - @imported = {} + @loading_helper = Helper.new end - def load_until(namespaces, name) - return nil if name == "" # special-case main. - name2files(namespaces, name).each do |filename| - modname = begin - import_if_possible(filename) + # Try to load the object with the given fully qualified name. + def try_load_fqname(type, fqname) + return nil if fqname == "" # special-case main. + name2files(fqname).each do |filename| + begin + imported_types = import(filename) + if result = imported_types.find { |t| t.type == type and t.name == fqname } + Puppet.debug "Automatically imported #{fqname} from #{filename} into #{environment}" + return result + end rescue Puppet::ImportError => detail # We couldn't load the item # I'm not convienced we should just drop these errors, but this # preserves existing behaviours. - nil - end - if result = yield(filename) - Puppet.info "Automatically imported #{name} from #{filename} into #{environment}" - result.module_name = modname if modname and result.respond_to?(:module_name=) - return result end end - nil - end - - def loaded?(name) - @loaded.include?(name) - end - - def name2files(namespaces, name) - return [name.sub(/^::/, '').gsub("::", File::SEPARATOR)] if name =~ /^::/ - - result = namespaces.inject([]) do |names_to_try, namespace| - fullname = (namespace + "::#{name}").sub(/^::/, '') - - # Try to load the module init file if we're a qualified name - names_to_try << fullname.split("::")[0] if fullname.include?("::") - - # Then the fully qualified name - names_to_try << fullname - end - - # Otherwise try to load the bare name on its own. This - # is appropriate if the class we're looking for is in a - # module that's different from our namespace. - result << name - result.uniq.collect { |f| f.gsub("::", File::SEPARATOR) } + # Nothing found. + return nil end def parse_file(file) Puppet.debug("importing '#{file}' in environment #{environment}") parser = Puppet::Parser::Parser.new(environment) parser.file = file - parser.parse + return parser.parse end - # Utility method factored out of load for handling thread-safety. - # This isn't tested in the specs, because that's basically impossible. - def import_if_possible(file, current_file = nil) - @loaded[file] || begin - case @loading.owner_of(file) - when :this_thread - nil - when :another_thread - import_if_possible(file,current_file) - when :nobody - @loaded[file] = import(file,current_file) - end - ensure - @loading.done_with(file) + private + + # Return a list of all file basenames that should be tried in order + # to load the object with the given fully qualified name. + def name2files(fqname) + result = [] + ary = fqname.split("::") + while ary.length > 0 + result << ary.join(File::SEPARATOR) + ary.pop end + return result end + end diff --git a/lib/puppet/property.rb b/lib/puppet/property.rb index 282a52cf4..84e1a0360 100644 --- a/lib/puppet/property.rb +++ b/lib/puppet/property.rb @@ -55,10 +55,10 @@ class Puppet::Property < Puppet::Parameter # * <tt>:required_features</tt>: A list of features this value requires. # * <tt>:event</tt>: The event that should be returned when this value is set. # * <tt>:call</tt>: When to call any associated block. The default value - # is ``instead``, which means to call the value instead of calling the - # provider. You can also specify ``before`` or ``after``, which will + # is `instead`, which means to call the value instead of calling the + # provider. You can also specify `before` or `after`, which will # call both the block and the provider, according to the order you specify - # (the ``first`` refers to when the block is called, not the provider). + # (the `first` refers to when the block is called, not the provider). def self.newvalue(name, options = {}, &block) value = value_collection.newvalue(name, options, &block) @@ -181,10 +181,10 @@ class Puppet::Property < Puppet::Parameter def log(msg) Puppet::Util::Log.create( - + :level => resource[:loglevel], :message => msg, - + :source => self ) end diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb index 8f993dbc1..4456feb4e 100644 --- a/lib/puppet/provider.rb +++ b/lib/puppet/provider.rb @@ -12,7 +12,7 @@ class Puppet::Provider Puppet::Util.logmethods(self, true) class << self - # Include the util module so we have access to things like 'binary' + # Include the util module so we have access to things like 'which' include Puppet::Util, Puppet::Util::Docs include Puppet::Util::Logging attr_accessor :name @@ -43,7 +43,7 @@ class Puppet::Provider raise Puppet::DevError, "No command #{name} defined for provider #{self.name}" end - binary(command) + which(command) end # Define commands that are not optional. @@ -205,7 +205,7 @@ class Puppet::Provider dochook(:defaults) do if @defaults.length > 0 return " Default for " + @defaults.collect do |f, v| - "``#{f}`` == ``#{v}``" + "`#{f}` == `#{v}`" end.join(" and ") + "." end end @@ -213,7 +213,7 @@ class Puppet::Provider dochook(:commands) do if @commands.length > 0 return " Required binaries: " + @commands.collect do |n, c| - "``#{c}``" + "`#{c}`" end.join(", ") + "." end end @@ -221,7 +221,7 @@ class Puppet::Provider dochook(:features) do if features.length > 0 return " Supported features: " + features.collect do |f| - "``#{f}``" + "`#{f}`" end.join(", ") + "." end end diff --git a/lib/puppet/provider/confine/exists.rb b/lib/puppet/provider/confine/exists.rb index 085118b2a..09f94dfd9 100644 --- a/lib/puppet/provider/confine/exists.rb +++ b/lib/puppet/provider/confine/exists.rb @@ -6,10 +6,7 @@ class Puppet::Provider::Confine::Exists < Puppet::Provider::Confine end def pass?(value) - if for_binary? - return false unless value = binary(value) - end - value and FileTest.exist?(value) + value && (for_binary? ? which(value) : FileTest.exist?(value)) end def message(value) diff --git a/lib/puppet/provider/group/groupadd.rb b/lib/puppet/provider/group/groupadd.rb index e661ddd7f..82ed4c0c7 100644 --- a/lib/puppet/provider/group/groupadd.rb +++ b/lib/puppet/provider/group/groupadd.rb @@ -1,7 +1,7 @@ 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. + desc "Group management via `groupadd` and its ilk. The default for most platforms diff --git a/lib/puppet/provider/group/ldap.rb b/lib/puppet/provider/group/ldap.rb index 2737feea6..86c72a5d3 100644 --- a/lib/puppet/provider/group/ldap.rb +++ b/lib/puppet/provider/group/ldap.rb @@ -1,11 +1,11 @@ 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 + ldap-related settings, including `ldapbase`. You will also almost + definitely need settings for `ldapuser` and `ldappassword`, so that your clients can write to ldap. Note that this provider will automatically generate a GID for you if you do diff --git a/lib/puppet/provider/group/pw.rb b/lib/puppet/provider/group/pw.rb index e3dd714ee..a054d1ff1 100644 --- a/lib/puppet/provider/group/pw.rb +++ b/lib/puppet/provider/group/pw.rb @@ -1,7 +1,7 @@ require 'puppet/provider/nameservice/pw' Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService::PW do - desc "Group management via ``pw``. + desc "Group management via `pw`. Only works on FreeBSD. diff --git a/lib/puppet/provider/host/parsed.rb b/lib/puppet/provider/host/parsed.rb index 4f15eff3f..a303c4bcf 100644 --- a/lib/puppet/provider/host/parsed.rb +++ b/lib/puppet/provider/host/parsed.rb @@ -8,66 +8,36 @@ else end - Puppet::Type.type(:host).provide( - :parsed, - :parent => Puppet::Provider::ParsedFile, - :default_target => hosts, - - :filetype => :flat -) do +Puppet::Type.type(:host).provide(:parsed,:parent => Puppet::Provider::ParsedFile, + :default_target => hosts,:filetype => :flat) do confine :exists => hosts text_line :comment, :match => /^#/ text_line :blank, :match => /^\s*$/ - record_line :parsed, :fields => %w{ip name host_aliases}, - :optional => %w{host_aliases}, - :rts => true do |line| - hash = {} - if line.sub!(/^(\S+)\s+(\S+)\s*/, '') - hash[:ip] = $1 - hash[:name] = $2 - - if line.empty? - hash[:host_aliases] = [] + record_line :parsed, :fields => %w{ip name host_aliases comment}, + :optional => %w{host_aliases comment}, + :match => /^(\S+)\s+(\S+)\s*(.*?)?(?:\s*#\s*(.*))?$/, + :post_parse => proc { |hash| + # An absent comment should match "comment => ''" + hash[:comment] = '' if hash[:comment].nil? or hash[:comment] == :absent + unless hash[:host_aliases].nil? or hash[:host_aliases] == :absent + hash[:host_aliases] = hash[:host_aliases].split(/\s+/) else - line.sub!(/\s*/, '') - line.sub!(/^([^#]+)\s*/) do |value| - aliases = $1 - unless aliases =~ /^\s*$/ - hash[:host_aliases] = aliases.split(/\s+/) - end - - "" - end + hash[:host_aliases] = [] end - else - raise Puppet::Error, "Could not match '#{line}'" - end - - hash[:host_aliases] = [] if hash[:host_aliases] == "" - - return hash - end - - # Convert the current object into a host-style string. - def self.to_line(hash) - return super unless hash[:record_type] == :parsed - [:ip, :name].each do |n| - raise ArgumentError, "#{n} is a required attribute for hosts" unless hash[n] and hash[n] != :absent - end - - str = "#{hash[:ip]}\t#{hash[:name]}" - - if hash.include? :host_aliases and !hash[:host_aliases].empty? - if hash[:host_aliases].is_a? Array + }, + :to_line => proc { |hash| + [:ip, :name].each do |n| + raise ArgumentError, "#{n} is a required attribute for hosts" unless hash[n] and hash[n] != :absent + end + str = "#{hash[:ip]}\t#{hash[:name]}" + if hash.include? :host_aliases and !hash[:host_aliases].empty? str += "\t#{hash[:host_aliases].join("\t")}" - else - raise ArgumentError, "Host aliases must be specified as an array" end - end - - str - end + if hash.include? :comment and !hash[:comment].empty? + str += "\t# #{hash[:comment]}" + end + str + } end - diff --git a/lib/puppet/provider/maillist/mailman.rb b/lib/puppet/provider/maillist/mailman.rb index 4fdc20a69..633642af7 100755 --- a/lib/puppet/provider/maillist/mailman.rb +++ b/lib/puppet/provider/maillist/mailman.rb @@ -2,11 +2,11 @@ require 'puppet/provider/parsedfile' Puppet::Type.type(:maillist).provide(:mailman) do if [ "CentOS", "RedHat", "Fedora" ].any? { |os| Facter.value(:operatingsystem) == os } - commands :list_lists => "/usr/lib/mailman/bin/list_lists", :rmlist => "/usr/lib/mailman/bin/rmlist", :newlist => "/usr/lib/mailman/bin/newlist" + commands :list_lists => "/usr/lib/mailman/bin/list_lists --bare", :rmlist => "/usr/lib/mailman/bin/rmlist", :newlist => "/usr/lib/mailman/bin/newlist" commands :mailman => "/usr/lib/mailman/mail/mailman" else # This probably won't work for non-Debian installs, but this path is sure not to be in the PATH. - commands :list_lists => "list_lists", :rmlist => "rmlist", :newlist => "newlist" + commands :list_lists => "list_lists --bare", :rmlist => "rmlist", :newlist => "newlist" commands :mailman => "/var/lib/mailman/mail/mailman" end @@ -14,10 +14,9 @@ Puppet::Type.type(:maillist).provide(:mailman) do # Return a list of existing mailman instances. def self.instances - list_lists.split("\n").reject { |line| line.include?("matching mailing lists") }.collect do |line| - name, description = line.sub(/^\s+/, '').sub(/\s+$/, '').split(/\s+-\s+/) - description = :absent if description.include?("no description available") - new(:ensure => :present, :name => name, :description => description) + list_lists.split("\n").collect do |line| + name = line.strip + new(:ensure => :present, :name => name) end end diff --git a/lib/puppet/provider/mcx/mcxcontent.rb b/lib/puppet/provider/mcx/mcxcontent.rb index cb5adc698..3ad437b53 100644 --- a/lib/puppet/provider/mcx/mcxcontent.rb +++ b/lib/puppet/provider/mcx/mcxcontent.rb @@ -53,39 +53,31 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do confine :operatingsystem => :darwin defaultfor :operatingsystem => :darwin - # self.instances is all important. - # This is the only class method, it returns - # an array of instances of this class. def self.instances mcx_list = [] - for ds_type in TypeMap.keys + TypeMap.keys.each do |ds_type| ds_path = "/Local/Default/#{TypeMap[ds_type]}" output = dscl 'localhost', '-list', ds_path member_list = output.split - for ds_name in member_list + member_list.each do |ds_name| content = mcxexport(ds_type, ds_name) if content.empty? Puppet.debug "/#{TypeMap[ds_type]}/#{ds_name} has no MCX data." else # This node has MCX data. - rsrc = self.new( - :name => "/#{TypeMap[ds_type]}/#{ds_name}", - :ds_type => ds_type, - :ds_name => ds_name, - - :content => content) - mcx_list << rsrc + mcx_list << self.new( + :name => "/#{TypeMap[ds_type]}/#{ds_name}", + :ds_type => ds_type, + :ds_name => ds_name, + :content => content + ) end end end mcx_list end - private - - # mcxexport is used by instances, and therefore - # a class method. def self.mcxexport(ds_type, ds_name) ds_t = TypeMap[ds_type] ds_n = ds_name.to_s @@ -93,9 +85,49 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do dscl 'localhost', '-mcxexport', ds_path end + + def create + self.content=(resource[:content]) + end + + def destroy + ds_parms = get_dsparams + ds_t = TypeMap[ds_parms[:ds_type]] + ds_n = ds_parms[:ds_name].to_s + ds_path = "/Local/Default/#{ds_t}/#{ds_n}" + + dscl 'localhost', '-mcxdelete', ds_path + end + + def exists? + begin + has_mcx? + rescue Puppet::ExecutionFailure => e + return false + end + end + + def content + ds_parms = get_dsparams + + self.class.mcxexport(ds_parms[:ds_type], ds_parms[:ds_name]) + end + + def content=(value) + # dscl localhost -mcximport + ds_parms = get_dsparams + + mcximport(ds_parms[:ds_type], ds_parms[:ds_name], resource[:content]) + end + + private + + def has_mcx? + !content.empty? + end + def mcximport(ds_type, ds_name, val) ds_t = TypeMap[ds_type] - ds_n = ds_name.to_s ds_path = "/Local/Default/#{ds_t}/#{ds_name}" tmp = Tempfile.new('puppet_mcx') @@ -111,33 +143,31 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do # Given the resource name string, parse ds_type out. def parse_type(name) - tmp = name.split('/')[1] - if ! tmp.is_a? String + ds_type = name.split('/')[1] + unless ds_type raise MCXContentProviderException, "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter." end # De-pluralize and downcase. - tmp = tmp.chop.downcase.to_sym - if not TypeMap.keys.member? tmp + ds_type = ds_type.chop.downcase.to_sym + unless TypeMap.key? ds_type raise MCXContentProviderException, "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter." end - tmp + ds_type end # Given the resource name string, parse ds_name out. def parse_name(name) ds_name = name.split('/')[2] - if ! ds_name.is_a? String + unless ds_name raise MCXContentProviderException, "Could not parse ds_name from resource name '#{name}'. Specify with ds_name parameter." end ds_name end - # Gather ds_type and ds_name from resource or - # parse it out of the name. - # This is a private instance method, not a class method. + # Gather ds_type and ds_name from resource or parse it out of the name. def get_dsparams ds_type = resource[:ds_type] ds_type ||= parse_type(resource[:name]) @@ -146,60 +176,10 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do ds_name = resource[:ds_name] ds_name ||= parse_name(resource[:name]) - rval = { + { :ds_type => ds_type.to_sym, :ds_name => ds_name, } - - return rval - - end - - public - - def create - self.content=(resource[:content]) - end - - def destroy - ds_parms = get_dsparams - ds_t = TypeMap[ds_parms[:ds_type]] - ds_n = ds_parms[:ds_name].to_s - ds_path = "/Local/Default/#{ds_t}/#{ds_n}" - - dscl 'localhost', '-mcxdelete', ds_path - end - - def exists? - # JJM Just re-use the content method and see if it's empty. - begin - mcx = content - rescue Puppet::ExecutionFailure => e - return false - end - has_mcx = ! mcx.empty? - end - - def content - ds_parms = get_dsparams - - mcx = self.class.mcxexport( - ds_parms[:ds_type], - - ds_parms[:ds_name]) - mcx - end - - def content=(value) - # dscl localhost -mcximport - ds_parms = get_dsparams - - mcx = mcximport( - ds_parms[:ds_type], - ds_parms[:ds_name], - - resource[:content]) - mcx end end diff --git a/lib/puppet/provider/mount.rb b/lib/puppet/provider/mount.rb index 393ae56c9..8c7b24bd4 100644 --- a/lib/puppet/provider/mount.rb +++ b/lib/puppet/provider/mount.rb @@ -41,7 +41,7 @@ module Puppet::Provider::Mount case platform when "Darwin" line =~ / on #{name} / or line =~ %r{ on /private/var/automount#{name}} - when "Solaris" + when "Solaris", "HP-UX" line =~ /^#{name} on / else line =~ / on #{name} / diff --git a/lib/puppet/provider/nameservice.rb b/lib/puppet/provider/nameservice.rb index 7339b646e..d57052bd9 100644 --- a/lib/puppet/provider/nameservice.rb +++ b/lib/puppet/provider/nameservice.rb @@ -165,6 +165,9 @@ class Puppet::Provider::NameService < Puppet::Provider begin execute(self.addcmd) + if feature?(:manages_password_age) && (cmd = passcmd) + execute(cmd) + end rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}" end diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb index 965a2aa60..106d99eb3 100644 --- a/lib/puppet/provider/nameservice/directoryservice.rb +++ b/lib/puppet/provider/nameservice/directoryservice.rb @@ -321,6 +321,31 @@ class DirectoryService < Puppet::Provider::NameService password_hash end + # Unlike most other *nixes, OS X doesn't provide built in functionality + # for automatically assigning uids and gids to accounts, so we set up these + # methods for consumption by functionality like --mkusers + # By default we restrict to a reasonably sane range for system accounts + def self.next_system_id(id_type, min_id=20) + dscl_args = ['.', '-list'] + if id_type == 'uid' + dscl_args << '/Users' << 'uid' + elsif id_type == 'gid' + dscl_args << '/Groups' << 'gid' + else + fail("Invalid id_type #{id_type}. Only 'uid' and 'gid' supported") + end + dscl_out = dscl(dscl_args) + # We're ok with throwing away negative uids here. + ids = dscl_out.split.compact.collect { |l| l.to_i if l.match(/^\d+$/) } + ids.compact!.sort! { |a,b| a.to_f <=> b.to_f } + # We're just looking for an unused id in our sorted array. + ids.each_index do |i| + next_id = ids[i] + 1 + return next_id if ids[i+1] != next_id and next_id >= min_id + end + end + + def ensure=(ensure_value) super # We need to loop over all valid properties for the type we're @@ -422,7 +447,14 @@ class DirectoryService < Puppet::Provider::NameService # Now we create all the standard properties Puppet::Type.type(@resource.class.name).validproperties.each do |property| next if property == :ensure - if value = @resource.should(property) and value != "" + value = @resource.should(property) + if property == :gid and value.nil? + value = self.class.next_system_id(id_type='gid') + end + if property == :uid and value.nil? + value = self.class.next_system_id(id_type='uid') + end + if value != "" and not value.nil? if property == :members add_members(nil, value) else diff --git a/lib/puppet/provider/nameservice/objectadd.rb b/lib/puppet/provider/nameservice/objectadd.rb index 80c142982..dbb9f306f 100644 --- a/lib/puppet/provider/nameservice/objectadd.rb +++ b/lib/puppet/provider/nameservice/objectadd.rb @@ -13,7 +13,8 @@ class ObjectAdd < Puppet::Provider::NameService end def modifycmd(param, value) - cmd = [command(:modify), flag(param), value] + cmd = [command(param.to_s =~ /password_.+_age/ ? :password : :modify)] + cmd << flag(param) << value if @resource.allowdupe? && ((param == :uid) || (param == :gid and self.class.name == :groupadd)) cmd << "-o" end diff --git a/lib/puppet/provider/package/apple.rb b/lib/puppet/provider/package/apple.rb index 0946de47f..b5bb9102f 100755 --- a/lib/puppet/provider/package/apple.rb +++ b/lib/puppet/provider/package/apple.rb @@ -5,7 +5,7 @@ Puppet::Type.type(:package).provide :apple, :parent => Puppet::Provider::Package desc "Package management based on OS X's builtin packaging system. This is essentially the simplest and least functional package system in existence -- it only supports installation; no deletion or upgrades. The provider will - automatically add the ``.pkg`` extension, so leave that off when specifying + automatically add the `.pkg` extension, so leave that off when specifying the package name." confine :operatingsystem => :darwin diff --git a/lib/puppet/provider/package/apt.rb b/lib/puppet/provider/package/apt.rb index d055e7552..2fc787419 100755 --- a/lib/puppet/provider/package/apt.rb +++ b/lib/puppet/provider/package/apt.rb @@ -2,7 +2,7 @@ Puppet::Type.type(:package).provide :apt, :parent => :dpkg, :source => :dpkg do # Provide sorting functionality include Puppet::Util::Package - desc "Package management via ``apt-get``." + desc "Package management via `apt-get`." has_feature :versionable @@ -14,6 +14,10 @@ Puppet::Type.type(:package).provide :apt, :parent => :dpkg, :source => :dpkg do ENV['DEBIAN_FRONTEND'] = "noninteractive" + # disable common apt helpers to allow non-interactive package installs + ENV['APT_LISTBUGS_FRONTEND'] = "none" + ENV['APT_LISTCHANGES_FRONTEND'] = "none" + # A derivative of DPKG; this is how most people actually manage # Debian boxes, and the only thing that differs is that it can # install packages from remote sites. diff --git a/lib/puppet/provider/package/aptitude.rb b/lib/puppet/provider/package/aptitude.rb index 557e657a4..8bdf984e6 100755 --- a/lib/puppet/provider/package/aptitude.rb +++ b/lib/puppet/provider/package/aptitude.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :aptitude, :parent => :apt, :source => :dpkg do - desc "Package management via ``aptitude``." + desc "Package management via `aptitude`." has_feature :versionable diff --git a/lib/puppet/provider/package/aptrpm.rb b/lib/puppet/provider/package/aptrpm.rb index d7842089f..2eb33c72b 100644 --- a/lib/puppet/provider/package/aptrpm.rb +++ b/lib/puppet/provider/package/aptrpm.rb @@ -2,7 +2,7 @@ Puppet::Type.type(:package).provide :aptrpm, :parent => :rpm, :source => :rpm do # Provide sorting functionality include Puppet::Util::Package - desc "Package management via ``apt-get`` ported to ``rpm``." + desc "Package management via `apt-get` ported to `rpm`." has_feature :versionable diff --git a/lib/puppet/provider/package/blastwave.rb b/lib/puppet/provider/package/blastwave.rb index 9f1f1ec19..e9c84845f 100755 --- a/lib/puppet/provider/package/blastwave.rb +++ b/lib/puppet/provider/package/blastwave.rb @@ -1,6 +1,6 @@ # Packaging using Blastwave's pkg-get program. Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun do - desc "Package management using Blastwave.org's ``pkg-get`` command on Solaris." + desc "Package management using Blastwave.org's `pkg-get` command on Solaris." pkgget = "pkg-get" pkgget = "/opt/csw/bin/pkg-get" if FileTest.executable?("/opt/csw/bin/pkg-get") diff --git a/lib/puppet/provider/package/dpkg.rb b/lib/puppet/provider/package/dpkg.rb index bee63bfba..7b34b09af 100755 --- a/lib/puppet/provider/package/dpkg.rb +++ b/lib/puppet/provider/package/dpkg.rb @@ -1,8 +1,8 @@ require 'puppet/provider/package' Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package do - desc "Package management via ``dpkg``. Because this only uses ``dpkg`` - and not ``apt``, you must specify the source of any packages you want + desc "Package management via `dpkg`. Because this only uses `dpkg` + and not `apt`, you must specify the source of any packages you want to manage." has_feature :holdable diff --git a/lib/puppet/provider/package/fink.rb b/lib/puppet/provider/package/fink.rb index 5cf47860e..db991397a 100755 --- a/lib/puppet/provider/package/fink.rb +++ b/lib/puppet/provider/package/fink.rb @@ -2,7 +2,7 @@ Puppet::Type.type(:package).provide :fink, :parent => :dpkg, :source => :dpkg do # Provide sorting functionality include Puppet::Util::Package - desc "Package management via ``fink``." + desc "Package management via `fink`." commands :fink => "/sw/bin/fink" commands :aptget => "/sw/bin/apt-get" diff --git a/lib/puppet/provider/package/gem.rb b/lib/puppet/provider/package/gem.rb index 8d70b756f..19414cec4 100755 --- a/lib/puppet/provider/package/gem.rb +++ b/lib/puppet/provider/package/gem.rb @@ -3,7 +3,7 @@ require 'uri' # Ruby gems support. Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package do - desc "Ruby Gem support. If a URL is passed via ``source``, then that URL is used as the + desc "Ruby Gem support. If a URL is passed via `source`, then that URL is used as the remote gem repository; if a source is present but is not a valid URL, it will be interpreted as the path to a local gem file. If source is not present at all, the gem will be installed from the default gem repositories." diff --git a/lib/puppet/provider/package/openbsd.rb b/lib/puppet/provider/package/openbsd.rb index ca477e56a..bb07d894a 100755 --- a/lib/puppet/provider/package/openbsd.rb +++ b/lib/puppet/provider/package/openbsd.rb @@ -2,8 +2,7 @@ require 'puppet/provider/package' # Packaging on OpenBSD. Doesn't work anywhere else that I know of. Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Package do - include Puppet::Util::Execution - desc "OpenBSD's form of ``pkg_add`` support." + desc "OpenBSD's form of `pkg_add` support." commands :pkginfo => "pkg_info", :pkgadd => "pkg_add", :pkgdelete => "pkg_delete" @@ -61,18 +60,15 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa "You must specify a package source for BSD packages" end - old_ensure = @resource[:ensure] - - if @resource[:source] =~ /\/$/ - withenv :PKG_PATH => @resource[:source] do - @resource[:ensure] = old_ensure if (@resource[:ensure] = get_version) == nil - full_name = [ @resource[:name], @resource[:ensure], @resource[:flavor] ] - pkgadd full_name.join('-').chomp('-') - end + if @resource[:source][-1,1] == ::File::PATH_SEPARATOR + e_vars = { :PKG_PATH => @resource[:source] } + full_name = [ @resource[:name], get_version || @resource[:ensure], @resource[:flavor] ].join('-').chomp('-') else - pkgadd @resource[:source] + e_vars = {} + full_name = @resource[:source] end + Puppet::Util::Execution::withenv(e_vars) { pkgadd full_name } end def get_version diff --git a/lib/puppet/provider/package/rpm.rb b/lib/puppet/provider/package/rpm.rb index d33a4f2f3..72dc260a4 100755 --- a/lib/puppet/provider/package/rpm.rb +++ b/lib/puppet/provider/package/rpm.rb @@ -1,7 +1,7 @@ require 'puppet/provider/package' # RPM packaging. Should work anywhere that has rpm installed. Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Provider::Package do - desc "RPM packaging support; should work anywhere with a working ``rpm`` + desc "RPM packaging support; should work anywhere with a working `rpm` binary." has_feature :versionable diff --git a/lib/puppet/provider/package/rug.rb b/lib/puppet/provider/package/rug.rb index 7028cc9e5..28729952d 100644 --- a/lib/puppet/provider/package/rug.rb +++ b/lib/puppet/provider/package/rug.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :rug, :parent => :rpm do - desc "Support for suse ``rug`` package manager." + desc "Support for suse `rug` package manager." has_feature :versionable diff --git a/lib/puppet/provider/package/sunfreeware.rb b/lib/puppet/provider/package/sunfreeware.rb index 53f03ed6e..4745ea1eb 100755 --- a/lib/puppet/provider/package/sunfreeware.rb +++ b/lib/puppet/provider/package/sunfreeware.rb @@ -1,7 +1,7 @@ # At this point, it's an exact copy of the Blastwave stuff. Puppet::Type.type(:package).provide :sunfreeware, :parent => :blastwave, :source => :sun do - desc "Package management using sunfreeware.com's ``pkg-get`` command on Solaris. - At this point, support is exactly the same as ``blastwave`` support and + desc "Package management using sunfreeware.com's `pkg-get` command on Solaris. + At this point, support is exactly the same as `blastwave` support and has not actually been tested." commands :pkgget => "pkg-get" diff --git a/lib/puppet/provider/package/up2date.rb b/lib/puppet/provider/package/up2date.rb index 5ff32bedc..243bc6c6b 100644 --- a/lib/puppet/provider/package/up2date.rb +++ b/lib/puppet/provider/package/up2date.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :up2date, :parent => :rpm, :source => :rpm do - desc "Support for Red Hat's proprietary ``up2date`` package update + desc "Support for Red Hat's proprietary `up2date` package update mechanism." commands :up2date => "/usr/sbin/up2date-nox" diff --git a/lib/puppet/provider/package/urpmi.rb b/lib/puppet/provider/package/urpmi.rb index 88a17ccb4..425d77849 100644 --- a/lib/puppet/provider/package/urpmi.rb +++ b/lib/puppet/provider/package/urpmi.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :urpmi, :parent => :rpm, :source => :rpm do - desc "Support via ``urpmi``." + desc "Support via `urpmi`." commands :urpmi => "urpmi", :urpmq => "urpmq", :rpm => "rpm" if command('rpm') diff --git a/lib/puppet/provider/package/yum.rb b/lib/puppet/provider/package/yum.rb index 07f68ddb1..6ed966fbd 100755 --- a/lib/puppet/provider/package/yum.rb +++ b/lib/puppet/provider/package/yum.rb @@ -1,5 +1,6 @@ +require 'puppet/util/package' Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do - desc "Support via ``yum``." + desc "Support via `yum`." has_feature :versionable @@ -52,6 +53,7 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do should = @resource.should(:ensure) self.debug "Ensuring => #{should}" wanted = @resource[:name] + operation = :install # XXX: We don't actually deal with epochs here. case should @@ -61,9 +63,14 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do else # Add the package version wanted += "-#{should}" + is = self.query + if is && Puppet::Util::Package.versioncmp(should, is[:ensure]) < 0 + self.debug "Downgrading package #{@resource[:name]} from version #{is[:ensure]} to #{should}" + operation = :downgrade + end end - output = yum "-d", "0", "-e", "0", "-y", :install, wanted + output = yum "-d", "0", "-e", "0", "-y", operation, wanted is = self.query raise Puppet::Error, "Could not find package #{self.name}" unless is diff --git a/lib/puppet/provider/package/zypper.rb b/lib/puppet/provider/package/zypper.rb index d56c72549..f129ef6e6 100644 --- a/lib/puppet/provider/package/zypper.rb +++ b/lib/puppet/provider/package/zypper.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :zypper, :parent => :rpm do - desc "Support for SuSE ``zypper`` package manager. Found in SLES10sp2+ and SLES11" + desc "Support for SuSE `zypper` package manager. Found in SLES10sp2+ and SLES11" has_feature :versionable diff --git a/lib/puppet/provider/service/base.rb b/lib/puppet/provider/service/base.rb index 70d764187..211e7f964 100755 --- a/lib/puppet/provider/service/base.rb +++ b/lib/puppet/provider/service/base.rb @@ -5,7 +5,7 @@ Puppet::Type.type(:service).provide :base do 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``. + akin to how you would do so using `init`. " diff --git a/lib/puppet/provider/service/bsd.rb b/lib/puppet/provider/service/bsd.rb index 2e00c33f1..e2a0e35f7 100644 --- a/lib/puppet/provider/service/bsd.rb +++ b/lib/puppet/provider/service/bsd.rb @@ -1,8 +1,8 @@ # 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 "FreeBSD's (and probably NetBSD?) form of `init`-style service management. - Uses ``rc.conf.d`` for service enabling and disabling. + Uses `rc.conf.d` for service enabling and disabling. " diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb index 4379f1b59..3d09e2849 100755 --- a/lib/puppet/provider/service/debian.rb +++ b/lib/puppet/provider/service/debian.rb @@ -1,10 +1,10 @@ # 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 "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``. + via `update-rc.d` and determines enabled status via `invoke-rc.d`. " diff --git a/lib/puppet/provider/service/freebsd.rb b/lib/puppet/provider/service/freebsd.rb index 10970e4da..f8c7134f0 100644 --- a/lib/puppet/provider/service/freebsd.rb +++ b/lib/puppet/provider/service/freebsd.rb @@ -18,6 +18,9 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do 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 @@ -44,7 +47,7 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do def rcvar_value value = self.rcvar[1] self.error("No rcvar value found in rcvar") if value.nil? - value = value.gsub!(/(.*)_enable=\"?(.*)\"?/, '\2') + value = value.gsub!(/(.*)_enable="?(\w+)"?/, '\2') self.error("rcvar value is empty") if value.nil? self.debug("rcvar value is #{value}") value @@ -78,7 +81,7 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do # Add a new setting to the rc files def rc_add(service, rcvar, yesno) - append = "\n\# Added by Puppet\n#{rcvar}_enable=\"#{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) { diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb index 08250a06a..382c74267 100644 --- a/lib/puppet/provider/service/gentoo.rb +++ b/lib/puppet/provider/service/gentoo.rb @@ -1,9 +1,9 @@ # 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 "Gentoo's form of `init`-style service management. - Uses ``rc-update`` for service enabling and disabling. + Uses `rc-update` for service enabling and disabling. " diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb index 6abff12db..447c01aa5 100755 --- a/lib/puppet/provider/service/init.rb +++ b/lib/puppet/provider/service/init.rb @@ -3,9 +3,9 @@ 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, + 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 + command or specify via `hasstatus` that one already exists in the init script. " diff --git a/lib/puppet/provider/service/launchd.rb b/lib/puppet/provider/service/launchd.rb index 970359539..1632edabf 100644 --- a/lib/puppet/provider/service/launchd.rb +++ b/lib/puppet/provider/service/launchd.rb @@ -38,6 +38,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do commands :launchctl => "/bin/launchctl" commands :sw_vers => "/usr/bin/sw_vers" + commands :plutil => "/usr/bin/plutil" defaultfor :operatingsystem => :darwin confine :operatingsystem => :darwin @@ -52,6 +53,12 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do Launchd_Overrides = "/var/db/launchd.db/com.apple.launchd/overrides.plist" + # 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 + # returns a label => path map for either all jobs, or just a single # job if the label is specified def self.jobsearch(label=nil) @@ -62,8 +69,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do next if f =~ /^\..*$/ next if FileTest.directory?(f) fullpath = File.join(path, f) - job = Plist::parse_xml(fullpath) - if job and job.has_key?("Label") + if FileTest.file?(fullpath) and job = read_plist(fullpath) and job.has_key?("Label") if job["Label"] == label return { label => fullpath } else @@ -118,8 +124,11 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do def plist_from_label(label) job = self.class.jobsearch(label) job_path = job[label] - job_plist = Plist::parse_xml(job_path) - raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}") if not job_plist + 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 @@ -200,9 +209,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled") if self.class.get_macosx_version_major == "10.6": - overrides = Plist::parse_xml(Launchd_Overrides) - - unless overrides.nil? + 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 @@ -227,7 +234,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do # versions this is stored in the job plist itself. def enable if self.class.get_macosx_version_major == "10.6" - overrides = Plist::parse_xml(Launchd_Overrides) + overrides = self.class.read_plist(Launchd_Overrides) overrides[resource[:name]] = { "Disabled" => false } Plist::Emit.save_plist(overrides, Launchd_Overrides) else @@ -242,7 +249,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do def disable if self.class.get_macosx_version_major == "10.6" - overrides = Plist::parse_xml(Launchd_Overrides) + overrides = self.class.read_plist(Launchd_Overrides) overrides[resource[:name]] = { "Disabled" => true } Plist::Emit.save_plist(overrides, Launchd_Overrides) else diff --git a/lib/puppet/provider/service/redhat.rb b/lib/puppet/provider/service/redhat.rb index 3ca67d66f..e851a488d 100755 --- a/lib/puppet/provider/service/redhat.rb +++ b/lib/puppet/provider/service/redhat.rb @@ -1,9 +1,9 @@ # 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: + desc "Red Hat's (and probably many others) form of `init`-style service management: - Uses ``chkconfig`` for service enabling and disabling. + Uses `chkconfig` for service enabling and disabling. " diff --git a/lib/puppet/provider/service/upstart.rb b/lib/puppet/provider/service/upstart.rb new file mode 100755 index 000000000..54971eeac --- /dev/null +++ b/lib/puppet/provider/service/upstart.rb @@ -0,0 +1,73 @@ +Puppet::Type.type(:service).provide :upstart, :parent => :init do + desc "Ubuntu service manager upstart. + + This provider manages upstart jobs which have replaced initd. + + 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/ssh_authorized_key/parsed.rb b/lib/puppet/provider/ssh_authorized_key/parsed.rb index 82f6b8881..6a3855c0e 100644 --- a/lib/puppet/provider/ssh_authorized_key/parsed.rb +++ b/lib/puppet/provider/ssh_authorized_key/parsed.rb @@ -61,6 +61,13 @@ require 'puppet/provider/parsedfile' Dir.mkdir(dir, dir_perm) File.chown(uid, nil, dir) end + + # ParsedFile usually calls backup_target much later in the flush process, + # but our SUID makes that fail to open filebucket files for writing. + # Fortunately, there's already logic to make sure it only ever happens once, + # so calling it here supresses the later attempt by our superclass's flush method. + self.class.backup_target(target) + Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super } File.chown(uid, nil, target) File.chmod(file_perm, target) diff --git a/lib/puppet/provider/user/hpux.rb b/lib/puppet/provider/user/hpux.rb index 50506c4cd..983970935 100644 --- a/lib/puppet/provider/user/hpux.rb +++ b/lib/puppet/provider/user/hpux.rb @@ -26,5 +26,4 @@ Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do 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 df082c569..75a9667b3 100644 --- a/lib/puppet/provider/user/ldap.rb +++ b/lib/puppet/provider/user/ldap.rb @@ -1,10 +1,10 @@ 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 + 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 + including `ldapbase`. You will also almost definitely need settings + for `ldapuser` and `ldappassword`, so that your clients can write to ldap. Note that this provider will automatically generate a UID for you if diff --git a/lib/puppet/provider/user/pw.rb b/lib/puppet/provider/user/pw.rb index 345d924bf..a5988cad1 100644 --- a/lib/puppet/provider/user/pw.rb +++ b/lib/puppet/provider/user/pw.rb @@ -1,7 +1,7 @@ require 'puppet/provider/nameservice/pw' Puppet::Type.type(:user).provide :pw, :parent => Puppet::Provider::NameService::PW do - desc "User management via ``pw`` on FreeBSD." + desc "User management via `pw` on FreeBSD." commands :pw => "pw" has_features :manages_homedir, :allows_duplicates diff --git a/lib/puppet/provider/user/user_role_add.rb b/lib/puppet/provider/user/user_role_add.rb index ea1b01b3b..2377f9e65 100644 --- a/lib/puppet/provider/user/user_role_add.rb +++ b/lib/puppet/provider/user/user_role_add.rb @@ -2,17 +2,19 @@ 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 management inherits `useradd` and adds logic to manage roles on Solaris using roleadd." defaultfor :operatingsystem => :solaris - commands :add => "useradd", :delete => "userdel", :modify => "usermod", :role_add => "roleadd", :role_delete => "roledel", :role_modify => "rolemod" + 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 @@ -22,14 +24,14 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => value !~ /\s/ end - has_features :manages_homedir, :allows_duplicates, :manages_solaris_rbac, :manages_passwords + 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].include?(property) + 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 @@ -79,6 +81,9 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => 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] @@ -140,14 +145,23 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => 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 the hashed pw (the second entry) + #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 - #got perl? - if ary = File.readlines("/etc/shadow").reject { |r| r =~ /^[^\w]/}.collect { |l| l.split(':')[0..1] }.find { |user, passwd| user == @resource[:name] } - pass = ary[1] - end - pass + 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 diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb index ec87694d7..ba406cc63 100644 --- a/lib/puppet/provider/user/useradd.rb +++ b/lib/puppet/provider/user/useradd.rb @@ -1,13 +1,15 @@ 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 the `Shadow Password` Ruby library often known as ruby-libshadow to manage user passwords." - commands :add => "useradd", :delete => "userdel", :modify => "usermod" + 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 @@ -17,9 +19,9 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ value !~ /\s/ end - has_features :manages_homedir, :allows_duplicates + has_features :manages_homedir, :allows_duplicates, :manages_expiry - has_feature :manages_passwords if Puppet.features.libshadow? + has_features :manages_passwords, :manages_password_age if Puppet.features.libshadow? def check_allow_dup @resource.allowdupe? ? ["-o"] : [] @@ -35,10 +37,20 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ cmd end + def check_manage_expiry + cmd = [] + if @resource[:expiry] + cmd << "-e #{@resource[:expiry]}" + end + + cmd + 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 != "" @@ -53,9 +65,37 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ cmd += add_properties cmd += check_allow_dup cmd += check_manage_home + cmd += check_manage_expiry 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? diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb index 414b1bc18..74805bb6f 100644 --- a/lib/puppet/rails.rb +++ b/lib/puppet/rails.rb @@ -2,6 +2,7 @@ require 'facter' require 'puppet' +require 'logger' module Puppet::Rails TIME_DEBUG = true @@ -22,9 +23,8 @@ module Puppet::Rails ActiveRecord::Base.logger.level = Logger::DEBUG end - if (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1) - ActiveRecord::Base.allow_concurrency = true - end + # As of ActiveRecord 2.2 allow_concurrency has been deprecated and no longer has any effect. + ActiveRecord::Base.allow_concurrency = true if Puppet::Util.activerecord_version < 2.2 ActiveRecord::Base.verify_active_connections! @@ -52,21 +52,17 @@ module Puppet::Rails args[:port] = Puppet[:dbport] unless Puppet[:dbport].to_s.empty? args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty? args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty? + args[:pool] = Puppet[:dbconnections].to_i unless Puppet[:dbconnections].to_i <= 0 args[:database] = Puppet[:dbname] args[:reconnect]= true socket = Puppet[:dbsocket] args[:socket] = socket unless socket.to_s.empty? - - connections = Puppet[:dbconnections].to_i - args[:pool] = connections if connections > 0 when "oracle_enhanced": args[:database] = Puppet[:dbname] unless Puppet[:dbname].to_s.empty? args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty? args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty? - - connections = Puppet[:dbconnections].to_i - args[:pool] = connections if connections > 0 + args[:pool] = Puppet[:dbconnections].to_i unless Puppet[:dbconnections].to_i <= 0 else raise ArgumentError, "Invalid db adapter #{adapter}" end diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb index 986cebd0a..b9dea2a3d 100644 --- a/lib/puppet/rails/host.rb +++ b/lib/puppet/rails/host.rb @@ -16,16 +16,6 @@ class Puppet::Rails::Host < ActiveRecord::Base belongs_to :source_file has_many :resources, :dependent => :destroy, :class_name => "Puppet::Rails::Resource" - # If the host already exists, get rid of its objects - def self.clean(host) - if obj = self.find_by_name(host) - obj.rails_objects.clear - return obj - else - return nil - end - end - def self.from_puppet(node) host = find_by_name(node.name) || new(:name => node.name) @@ -38,63 +28,6 @@ class Puppet::Rails::Host < ActiveRecord::Base host end - # Store our host in the database. - def self.store(node, resources) - args = {} - - host = nil - railsmark "Stored node" do - transaction do - #unless host = find_by_name(name) - - debug_benchmark("Searched for host")do - unless host = find_by_name(node.name) - host = new(:name => node.name) - end - end - if ip = node.parameters["ipaddress"] - host.ip = ip - end - - if env = node.environment - host.environment = env - end - - # Store the facts into the database. - host.merge_facts(node.parameters) - - debug_benchmark("Handled resources") { - host.merge_resources(resources) - } - - host.last_compile = Time.now - - debug_benchmark("Saved host") { - host.save - } - end - - end - - # This only runs if time debugging is enabled. - write_benchmarks - - host - end - - # Return the value of a fact. - def fact(name) - - if fv = self.fact_values.find( - :all, :include => :fact_name, - - :conditions => "fact_names.name = '#{name}'") - return fv - else - return nil - end - end - # returns a hash of fact_names.name => [ fact_values ] for this host. # Note that 'fact_values' is actually a list of the value instances, not # just actual values. @@ -305,11 +238,6 @@ class Puppet::Rails::Host < ActiveRecord::Base end end - def update_connect_time - self.last_connect = Time.now - save - end - def to_puppet node = Puppet::Node.new(self.name) {"ip" => "ipaddress", "environment" => "environment"}.each do |myparam, itsparam| diff --git a/lib/puppet/reference/configuration.rb b/lib/puppet/reference/configuration.rb index bfa2cb802..e6a8dc20f 100644 --- a/lib/puppet/reference/configuration.rb +++ b/lib/puppet/reference/configuration.rb @@ -33,7 +33,7 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc # Leave out the section information; it was apparently confusing people. #str += "- **Section**: #{object.section}\n" unless val == "" - str += "- **Default**: #{val}\n" + str += "- *Default*: #{val}\n" end str += "\n" end @@ -42,12 +42,11 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc end config.header = " -Specifying Configuration Parameters ------------------------------------ +## Specifying Configuration Parameters -On The Command-Line -+++++++++++++++++++ -Every Puppet executable (with the exception of ``puppetdoc``) accepts all of +### On The Command-Line + +Every Puppet executable (with the exception of `puppetdoc`) accepts all of the parameters below, but not all of the arguments make sense for every executable. I have tried to be as thorough as possible in the descriptions of the @@ -55,60 +54,59 @@ arguments, so it should be obvious whether an argument is appropriate or not. These parameters can be supplied to the executables either as command-line options or in the configuration file. For instance, the command-line -invocation below would set the configuration directory to ``/private/puppet``:: +invocation below would set the configuration directory to `/private/puppet`: - $ puppet agent --confdir=/private/puppet + $ puppet agent --confdir=/private/puppet Note that boolean options are turned on and off with a slightly different -syntax on the command line:: +syntax on the command line: - $ puppet agent --storeconfigs + $ puppet agent --storeconfigs - $ puppet agent --no-storeconfigs + $ puppet agent --no-storeconfigs The invocations above will enable and disable, respectively, the storage of the client configuration. -Configuration Files -+++++++++++++++++++ +### Configuration Files + As mentioned above, the configuration parameters can also be stored in a configuration file, located in the configuration directory. As root, the -default configuration directory is ``/etc/puppet``, and as a regular user, the -default configuration directory is ``~user/.puppet``. As of 0.23.0, all -executables look for ``puppet.conf`` in their configuration directory +default configuration directory is `/etc/puppet`, and as a regular user, the +default configuration directory is `~user/.puppet`. As of 0.23.0, all +executables look for `puppet.conf` in their configuration directory (although they previously looked for separate files). For example, -``puppet.conf`` is located at ``/etc/puppet/puppet.conf`` as root and -``~user/.puppet/puppet.conf`` as a regular user by default. +`puppet.conf` is located at `/etc/puppet/puppet.conf` as `root` and +`~user/.puppet/puppet.conf` as a regular user by default. + +All executables will set any parameters set within the `[main]` section, +and each executable will also use one of the `[master]`, `[agent]`. -All executables will set any parameters set within the ``main`` section, -and each executable will also use one of the ``master``, ``agent``, or -``user`` sections. +#### File Format -File Format -''''''''''' The file follows INI-style formatting. Here is an example of a very simple -``puppet.conf`` file:: +`puppet.conf` file: - [main] - confdir = /private/puppet - storeconfigs = true + [main] + confdir = /private/puppet + storeconfigs = true Note that boolean parameters must be explicitly specified as `true` or `false` as seen above. If you need to change file parameters (e.g., reset the mode or owner), do -so within curly braces on the same line:: +so within curly braces on the same line: - [main] - myfile = /tmp/whatever {owner = root, mode = 644} + [main] + myfile = /tmp/whatever {owner = root, mode = 644} If you're starting out with a fresh configuration, you may wish to let the executable generate a template configuration file for you by invoking the executable in question with the `--genconfig` command. The executable will print a template configuration to standard output, which can be -redirected to a file like so:: +redirected to a file like so: - $ puppet agent --genconfig > /etc/puppet/puppet.conf + $ puppet agent --genconfig > /etc/puppet/puppet.conf Note that this invocation will replace the contents of any pre-existing `puppet.conf` file, so make a backup of your present config if it contains @@ -117,28 +115,28 @@ valuable information. Like the `--genconfig` argument, the executables also accept a `--genmanifest` argument, which will generate a manifest that can be used to manage all of Puppet's directories and files and prints it to standard output. This can -likewise be redirected to a file:: +likewise be redirected to a file: - $ puppet agent --genmanifest > /etc/puppet/manifests/site.pp + $ puppet agent --genmanifest > /etc/puppet/manifests/site.pp Puppet can also create user and group accounts for itself (one `puppet` group -and one `puppet` user) if it is invoked as `root` with the `--mkusers` argument:: +and one `puppet` user) if it is invoked as `root` with the `--mkusers` argument: - $ puppet agent --mkusers + $ puppet agent --mkusers -Signals -------- -The ``puppet agent`` and ``puppet master`` executables catch some signals for special -handling. Both daemons catch (``SIGHUP``), which forces the server to restart -tself. Predictably, interrupt and terminate (``SIGINT`` and ``SIGTERM``) will shut -down the server, whether it be an instance of ``puppet agent`` or ``puppet master``. +## Signals -Sending the ``SIGUSR1`` signal to an instance of ``puppet agent`` will cause it to +The `puppet agent` and `puppet master` executables catch some signals for special +handling. Both daemons catch (`SIGHUP`), which forces the server to restart +tself. Predictably, interrupt and terminate (`SIGINT` and `SIGTERM`) will shut +down the server, whether it be an instance of `puppet agent` or `puppet master`. + +Sending the `SIGUSR1` signal to an instance of `puppet agent` will cause it to immediately begin a new configuration transaction with the server. This -signal has no effect on ``puppet master``. +signal has no effect on `puppet master`. + +## Configuration Parameter Reference -Configuration Parameter Reference ---------------------------------- Below is a list of all documented parameters. Not all of them are valid with all Puppet executables, but the executables will ignore any inappropriate values. diff --git a/lib/puppet/reference/indirection.rb b/lib/puppet/reference/indirection.rb index d14510c16..e5b076508 100644 --- a/lib/puppet/reference/indirection.rb +++ b/lib/puppet/reference/indirection.rb @@ -8,12 +8,12 @@ reference = Puppet::Util::Reference.newreference :indirection, :doc => "Indirect 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" + ("-" * name.length) + "\n\n" + text += "## " + indirection.to_s + "\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" + ("+" * terminus.to_s.length) + "\n\n" + text += "### " + terminus.to_s + "\n\n" term_class = Puppet::Indirector::Terminus.terminus_class(ind.name, terminus) @@ -26,9 +26,8 @@ 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. +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 6a319f1c2..c16a1d33a 100644 --- a/lib/puppet/reference/metaparameter.rb +++ b/lib/puppet/reference/metaparameter.rb @@ -9,16 +9,17 @@ metaparameter = Puppet::Util::Reference.newreference :metaparameter, :doc => "Al } 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 - ++++++++++++++++++++++++ - } +# 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| @@ -29,14 +30,6 @@ metaparameter = Puppet::Util::Reference.newreference :metaparameter, :doc => "Al a.to_s <=> b.to_s }.each { |param| str += paramwrap(param.to_s, scrub(Puppet::Type.metaparamdoc(param)), :level => 4) - #puts "<dt>#{param}</dt>" - #puts tab(1) + Puppet::Type.metaparamdoc(param).scrub.indent($tab)gsub(/\n\s*/,' ') - #puts "<dd>" - #puts indent(scrub(Puppet::Type.metaparamdoc(param)), $tab) - #puts scrub(Puppet::Type.metaparamdoc(param)) - #puts "</dd>" - - #puts "" } rescue => detail puts detail.backtrace diff --git a/lib/puppet/reference/network.rb b/lib/puppet/reference/network.rb index 15e4f6769..fda7931fb 100644 --- a/lib/puppet/reference/network.rb +++ b/lib/puppet/reference/network.rb @@ -29,11 +29,11 @@ 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``. +`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``. +`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 ef33a559b..c85ad23ab 100644 --- a/lib/puppet/reference/providers.rb +++ b/lib/puppet/reference/providers.rb @@ -47,7 +47,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider # Add the suitability note if missing = provider.suitable?(false) and missing.empty? - data << "**X**" + data << "*X*" suit = true functional = true else @@ -86,7 +86,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider # Add a note for every feature features.each do |feature| if provider.features.include?(feature) - data << "**X**" + data << "*X*" else data << "" end @@ -95,7 +95,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider ret += h(type.name.to_s + "_", 2) - ret += ".. _#{type.name}: #{"http://docs.puppetlabs.com/references/stable/type.html##{type.name}"}\n\n" + 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) @@ -111,7 +111,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider ret end providers.header = " -Puppet resource types are usually backed by multiple implementations called ``providers``, +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 diff --git a/lib/puppet/reference/report.rb b/lib/puppet/reference/report.rb index 481ca2dc1..47fc779ab 100644 --- a/lib/puppet/reference/report.rb +++ b/lib/puppet/reference/report.rb @@ -7,16 +7,15 @@ end report.header = " Puppet clients can report back to the server after each transaction. This transaction report is sent as a YAML dump of the -``Puppet::Transaction::Report`` class and includes every log message that was +`Puppet::Transaction::Report` class and includes every log message that was generated during the transaction along with as many metrics as Puppet knows how -to collect. See `ReportsAndReporting Reports and Reporting`:trac: -for more information on how to use reports. +to collect. See [Reports and Reporting](http://projects.puppetlabs.com/projects/puppet/wiki/Reports_And_Reporting) for more information on how to use reports. Currently, clients default to not sending in reports; you can enable reporting -by setting the ``report`` parameter to true. +by setting the `report` parameter to true. -To use a report, set the ``reports`` parameter on the server; multiple -reports must be comma-separated. You can also specify ``none`` to disable +To use a report, set the `reports` parameter on the server; multiple +reports must be comma-separated. You can also specify `none` to disable reports entirely. Puppet provides multiple report handlers that will process client reports: diff --git a/lib/puppet/reference/type.rb b/lib/puppet/reference/type.rb index be8742edc..b423387e9 100644 --- a/lib/puppet/reference/type.rb +++ b/lib/puppet/reference/type.rb @@ -5,34 +5,34 @@ type = Puppet::Util::Reference.newreference :type, :doc => "All Puppet resource 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 - -------------- +## Resource Types - - The *namevar* is the parameter used to uniquely identify a type instance. +- 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``. + worry about which parameter is the `namevar`. - In the following code:: + In the following code: - file { "/etc/passwd": - owner => root, - group => root, - mode => 644 - } + file { "/etc/passwd": + owner => root, + group => root, + 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. + `/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). + 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. diff --git a/lib/puppet/reports/http.rb b/lib/puppet/reports/http.rb index f1a74195d..7ac54dfbd 100644 --- a/lib/puppet/reports/http.rb +++ b/lib/puppet/reports/http.rb @@ -5,7 +5,7 @@ require 'uri' Puppet::Reports.register_report(:http) do desc <<-DESC - Send report information via HTTP to the ``reporturl``. Each host sends + Send report information via HTTP to the `reporturl`. Each host sends its report as a YAML dump and this sends this YAML to a client via HTTP POST. The YAML is the `report` parameter of the request." DESC diff --git a/lib/puppet/reports/rrdgraph.rb b/lib/puppet/reports/rrdgraph.rb index 9fbeb60e8..517fa8f03 100644 --- a/lib/puppet/reports/rrdgraph.rb +++ b/lib/puppet/reports/rrdgraph.rb @@ -1,12 +1,11 @@ Puppet::Reports.register_report(:rrdgraph) do desc "Graph all available data about hosts using the RRD library. You must have the Ruby RRDtool library installed to use this report, which - you can get from `the RubyRRDTool RubyForge page`_. This package may also - be available as ``ruby-rrd`` or ``rrdtool-ruby`` in your distribution's package - management system. The library and/or package will both require the binary - ``rrdtool`` package from your distribution to be installed. - - .. _the RubyRRDTool RubyForge page: http://rubyforge.org/projects/rubyrrdtool/ + you can get from + [the RubyRRDTool RubyForge page](http://rubyforge.org/projects/rubyrrdtool/). + This package may also be available as `ruby-rrd` or `rrdtool-ruby` in your + distribution's package management system. The library and/or package will both + require the binary `rrdtool` package from your distribution to be installed. This report will create, manage, and graph RRD database files for each of the metrics generated during transactions, and it will create a @@ -14,12 +13,12 @@ Puppet::Reports.register_report(:rrdgraph) do point, it will not create a common index file to display links to all hosts. - All RRD files and graphs get created in the ``rrddir`` directory. If + All RRD files and graphs get created in the `rrddir` directory. If you want to serve these publicly, you should be able to just alias that directory in a web server. - If you really know what you're doing, you can tune the ``rrdinterval``, - which defaults to the ``runinterval``." + If you really know what you're doing, you can tune the `rrdinterval`, + which defaults to the `runinterval`." def hostdir @hostdir ||= File.join(Puppet[:rrddir], self.host) @@ -123,7 +122,7 @@ Puppet::Reports.register_report(:rrdgraph) do # that means we record the total time, the config time, and that's about # it. We should probably send each type's time as a separate metric. def timeclean(metric) - metric.values = metric.values.find_all { |name, label, value| [:total, :config_retrieval].include?(name) } + metric.values = metric.values.find_all { |name, label, value| ['total', 'config_retrieval'].include?(name.to_s) } end end diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb index 65159fc07..30f24591c 100644 --- a/lib/puppet/reports/store.rb +++ b/lib/puppet/reports/store.rb @@ -2,7 +2,7 @@ require 'puppet' Puppet::Reports.register_report(:store) do desc "Store the yaml report on disk. Each host sends its report as a YAML dump - and this just stores the file on disk, in the ``reportdir`` directory. + and this just stores the file on disk, in the `reportdir` directory. These files collect quickly -- one every half hour -- so it is a good idea to perform some maintenance on them if you use this report (it's the only @@ -19,7 +19,7 @@ Puppet::Reports.register_report(:store) do :owner => 'service', :group => 'service' }, - + :noop => [false, "Used by settings internally."] ) diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb index 652104096..e17143e2f 100644 --- a/lib/puppet/reports/tagmail.rb +++ b/lib/puppet/reports/tagmail.rb @@ -6,12 +6,12 @@ require 'time' Puppet::Reports.register_report(:tagmail) do desc "This report sends specific log messages to specific email addresses - based on the tags in the log messages. See the - `UsingTags tag documentation`:trac: for more information - on tags. + based on the tags in the log messages. - To use this report, you must create a ``tagmail.conf`` (in the location - specified by ``tagmap``). This is a simple file that maps tags to + See the [UsingTags tag documentation](http://projects.puppetlabs.com/projects/puppet/wiki/Using_Tags) for more information on tags. + + To use this report, you must create a `tagmail.conf` (in the location + specified by `tagmap`). This is a simple file that maps tags to email addresses: Any log messages in the report that match the specified tags will be sent to the specified email addresses. @@ -20,21 +20,20 @@ Puppet::Reports.register_report(:tagmail) do the email addresses by a colon, and the email addresses should also be comma-separated. - Lastly, there is an ``all`` tag that will always match all log messages. + Lastly, there is an `all` tag that will always match all log messages. - Here is an example tagmail.conf:: + Here is an example `tagmail.conf`: - all: me@domain.com - webserver, !mailserver: httpadmins@domain.com + all: me@domain.com + webserver, !mailserver: httpadmins@domain.com - This will send all messages to ``me@domain.com``, and all messages from - webservers that are not also from mailservers to ``httpadmins@domain.com``. + This will send all messages to `me@domain.com`, and all messages from + webservers that are not also from mailservers to `httpadmins@domain.com`. If you are using anti-spam controls, such as grey-listing, on your mail - server you should whitelist the sending email (controlled by ``reportform`` configuration option) to ensure your email is not discarded as spam. + server you should whitelist the sending email (controlled by `reportform` configuration option) to ensure your email is not discarded as spam. " - # Find all matching messages. def match(taglists) matching_logs = [] @@ -85,7 +84,7 @@ Puppet::Reports.register_report(:tagmail) do pos = [] neg = [] taglist.sub(/\s+$/,'').split(/\s*,\s*/).each do |tag| - unless tag =~ /^!?[-\w]+$/ + unless tag =~ /^!?[-\w\.]+$/ raise ArgumentError, "Invalid tag #{tag.inspect}" end case tag diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb index 96d22e414..4f0d50750 100644 --- a/lib/puppet/resource.rb +++ b/lib/puppet/resource.rb @@ -13,7 +13,7 @@ class Puppet::Resource extend Puppet::Util::Pson include Enumerable attr_accessor :file, :line, :catalog, :exported, :virtual, :validate_parameters, :strict - attr_reader :namespaces + attr_reader :type, :title require 'puppet/indirector' extend Puppet::Indirector @@ -80,6 +80,18 @@ class Puppet::Resource end end + def yaml_property_munge(x) + case x + when Hash + x.inject({}) { |h,kv| + k,v = kv + h[k] = self.class.value_to_pson_data(v) + h + } + else self.class.value_to_pson_data(x) + end + end + def to_pson(*args) to_pson_data_hash.to_pson(*args) end @@ -154,33 +166,42 @@ class Puppet::Resource end end + # This stub class is only needed for serialization compatibility with 0.25.x + class Reference + attr_accessor :type,:title + def initialize(type,title) + @type,@title = type,title + end + end + # Create our resource. def initialize(type, title = nil, attributes = {}) @parameters = {} - @namespaces = [""] - # Set things like namespaces and strictness first. + # Set things like strictness first. attributes.each do |attr, value| next if attr == :parameters send(attr.to_s + "=", value) end - # We do namespaces first, and use tmp variables, so our title - # canonicalization works (i.e., namespaces are set and resource - # types can be looked up) - tmp_type, tmp_title = extract_type_and_title(type, title) - self.type = tmp_type - self.title = tmp_title + @type, @title = extract_type_and_title(type, title) + + @type = munge_type_name(@type) + + if @type == "Class" + @title = :main if @title == "" + @title = munge_type_name(@title) + end if params = attributes[:parameters] extract_parameters(params) end - resolve_type_and_title - tag(self.type) tag(self.title) if valid_tag?(self.title) + @reference = Reference.new(@type,@title) # for serialization compatibility with 0.25.x + raise ArgumentError, "Invalid resource type #{type}" if strict? and ! resource_type end @@ -193,17 +214,12 @@ class Puppet::Resource return(catalog ? catalog.resource(to_s) : nil) end - def title=(value) - @unresolved_title = value - @title = nil - end - def resource_type - @resource_type ||= case type - when "Class"; find_hostclass(title) - when "Node"; find_node(title) + case type + when "Class"; known_resource_types.hostclass(title == :main ? "" : title) + when "Node"; known_resource_types.node(title) else - find_resource_type(type) + Puppet::Type.type(type.to_s.downcase.to_sym) || known_resource_types.definition(type) end end @@ -314,28 +330,6 @@ class Puppet::Resource self end - # We have to lazy-evaluate this. - def title=(value) - @title = nil - @unresolved_title = value - end - - # We have to lazy-evaluate this. - def type=(value) - @type = nil - @unresolved_type = value || "Class" - end - - def title - resolve_type_and_title unless @title - @title - end - - def type - resolve_type_and_title unless @type - @type - end - def valid_parameter?(name) resource_type.valid_parameter?(name) end @@ -346,29 +340,6 @@ class Puppet::Resource private - def find_node(name) - known_resource_types.node(name) - end - - def find_hostclass(title) - name = title == :main ? "" : title - known_resource_types.find_hostclass(namespaces, name) - end - - def find_resource_type(type) - # It still works fine without the type == 'class' short-cut, but it is a lot slower. - return nil if ["class", "node"].include? type.to_s.downcase - find_builtin_resource_type(type) || find_defined_resource_type(type) - end - - def find_builtin_resource_type(type) - Puppet::Type.type(type.to_s.downcase.to_sym) - end - - def find_defined_resource_type(type) - known_resource_types.find_definition(namespaces, type.to_s.downcase) - end - # Produce a canonical method name. def parameter_name(param) param = param.to_s.downcase.to_sym @@ -378,10 +349,6 @@ class Puppet::Resource param end - def namespaces=(ns) - @namespaces = Array(ns) - end - # The namevar for our resource type. If the type doesn't exist, # always use :name. def namevar @@ -428,54 +395,9 @@ class Puppet::Resource value.to_s.split("::").collect { |s| s.capitalize }.join("::") end - # This is an annoyingly complicated method for resolving qualified - # types as necessary, and putting them in type or title attributes. - def resolve_type_and_title - if @unresolved_type - @type = resolve_type - @unresolved_type = nil - end - if @unresolved_title - @title = resolve_title - @unresolved_title = nil - end - end - - def resolve_type - case type = munge_type_name(@unresolved_type) - when "Class", "Node"; - type - else - # Otherwise, some kind of builtin or defined resource type - munge_type_name( (r = find_resource_type(type)) ? r.name : type) - end - end - - # This method only works if resolve_type was called first - def resolve_title - case @type - when "Node"; return @unresolved_title - when "Class"; - resolve_title_for_class(@unresolved_title) - else - @unresolved_title - end - end - - def resolve_title_for_class(title) - if title == "" or title == :main - return :main - end - - if klass = find_hostclass(title) - result = klass.name - end - munge_type_name(result || title) - end - def parse_title h = {} - type = find_resource_type(@type) + type = resource_type if type.respond_to? :title_patterns type.title_patterns.each { |regexp, symbols_and_lambdas| if captures = regexp.match(title.to_s) diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb index 4b4342d11..a8668d844 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -57,7 +57,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph end def title_key_for_ref( ref ) - ref =~ /^([\w:]+)\[(.*)\]$/m + ref =~ /^([-\w:]+)\[(.*)\]$/m [$1, $2] end diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index 85c0979c1..77824845d 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -13,8 +13,8 @@ class Puppet::Resource::Type RESOURCE_SUPERTYPES = [:hostclass, :node, :definition] - attr_accessor :file, :line, :doc, :code, :ruby_code, :parent, :resource_type_collection, :module_name - attr_reader :type, :namespace, :arguments, :behaves_like + attr_accessor :file, :line, :doc, :code, :ruby_code, :parent, :resource_type_collection + attr_reader :type, :namespace, :arguments, :behaves_like, :module_name RESOURCE_SUPERTYPES.each do |t| define_method("#{t}?") { self.type == t } @@ -69,6 +69,7 @@ class Puppet::Resource::Type end scope = subscope(scope, resource) unless resource.title == :main + scope.compiler.add_class(name) unless definition? set_resource_parameters(resource, scope) @@ -91,6 +92,8 @@ class Puppet::Resource::Type end set_arguments(options[:arguments]) + + @module_name = options[:module_name] end # This is only used for node names, and really only when the node name @@ -137,21 +140,15 @@ class Puppet::Resource::Type end end - # Make an instance of our resource type. This is only possible - # for those classes and nodes that don't have any arguments, and is - # only useful for things like the 'include' function. - def mk_plain_resource(scope) + # Make an instance of the resource type, and place it in the catalog + # if it isn't in the catalog already. This is only possible for + # classes and nodes. No parameters are be supplied--if this is a + # parameterized class, then all parameters take on their default + # values. + def ensure_in_catalog(scope) type == :definition and raise ArgumentError, "Cannot create resources for defined resource types" resource_type = type == :hostclass ? :class : :node - # Make sure our parent class has been evaluated, if we have one. - if parent - parent_resource = scope.catalog.resource(resource_type, parent) - unless parent_resource - parent_type(scope).mk_plain_resource(scope) - end - end - # Do nothing if the resource already exists; this makes sure we don't # get multiple copies of the class resource, which helps provide the # singleton nature of classes. @@ -160,11 +157,22 @@ class Puppet::Resource::Type end resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) + instantiate_resource(scope, resource) scope.compiler.add_resource(scope, resource) - scope.catalog.tag(*resource.tags) resource end + def instantiate_resource(scope, resource) + # Make sure our parent class has been evaluated, if we have one. + if parent && !scope.catalog.resource(resource.type, parent) + parent_type(scope).ensure_in_catalog(scope) + end + + if ['Class', 'Node'].include? resource.type + scope.catalog.tag(*resource.tags) + end + end + def name return @name unless @name.is_a?(Regexp) @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'') @@ -174,12 +182,29 @@ class Puppet::Resource::Type @name.is_a?(Regexp) end + # MQR TODO: + # + # The change(s) introduced by the fix for #4270 are mostly silly & should be + # removed, though we didn't realize it at the time. If it can be established/ + # ensured that nodes never call parent_type and that resource_types are always + # (as they should be) members of exactly one resource_type_collection the + # following method could / should be replaced with: + # + # def parent_type + # @parent_type ||= parent && ( + # resource_type_collection.find_or_load([name],parent,type.to_sym) || + # fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{resource_type_collection.environment}" + # ) + # end + # + # ...and then the rest of the changes around passing in scope reverted. + # def parent_type(scope = nil) return nil unless parent unless @parent_type raise "Must pass scope to parent_type when called first time" unless scope - unless @parent_type = scope.environment.known_resource_types.send("find_#{type}", scope.namespaces, parent) + unless @parent_type = scope.environment.known_resource_types.send("find_#{type}", [name], parent) fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{scope.environment}" end end @@ -215,8 +240,13 @@ class Puppet::Resource::Type resource[param] = value end - scope.setvar("title", resource.title) unless set.include? :title - scope.setvar("name", resource.name) unless set.include? :name + if @type == :hostclass + scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title + scope.setvar("name", resource.name.to_s.downcase ) unless set.include? :name + else + scope.setvar("title", resource.title ) unless set.include? :title + scope.setvar("name", resource.name ) unless set.include? :name + end scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) diff --git a/lib/puppet/resource/type_collection.rb b/lib/puppet/resource/type_collection.rb index 6a933362f..a96927613 100644 --- a/lib/puppet/resource/type_collection.rb +++ b/lib/puppet/resource/type_collection.rb @@ -19,6 +19,12 @@ class Puppet::Resource::TypeCollection @watched_files = {} end + def import_ast(ast, modname) + ast.instantiate(modname).each do |instance| + add(instance) + end + end + def <<(thing) add(thing) self @@ -92,50 +98,8 @@ class Puppet::Resource::TypeCollection @definitions[munge_name(name)] end - def find(namespaces, name, type) - #Array("") == [] for some reason - namespaces = [namespaces] unless namespaces.is_a?(Array) - - if r = find_fully_qualified(name, type) - return r - end - - namespaces.each do |namespace| - ary = namespace.split("::") - - while ary.length > 0 - tmp_namespace = ary.join("::") - if r = find_partially_qualified(tmp_namespace, name, type) - return r - end - - # Delete the second to last object, which reduces our namespace by one. - ary.pop - end - - if result = send(type, name) - return result - end - end - nil - end - - def find_or_load(namespaces, name, type) - name = name.downcase - namespaces = [namespaces] unless namespaces.is_a?(Array) - namespaces = namespaces.collect { |ns| ns.downcase } - - # This could be done in the load_until, but the knowledge seems to - # belong here. - if r = find(namespaces, name, type) - return r - end - - loader.load_until(namespaces, name) { find(namespaces, name, type) } - end - def find_node(namespaces, name) - find("", name, :node) + @nodes[munge_name(name)] end def find_hostclass(namespaces, name) @@ -152,23 +116,6 @@ class Puppet::Resource::TypeCollection end end - def perform_initial_import - parser = Puppet::Parser::Parser.new(environment) - if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != "" - parser.string = code - else - file = Puppet.settings.value(:manifest, environment.to_s) - return unless File.exist?(file) - parser.file = file - end - parser.parse - rescue => detail - msg = "Could not parse for environment #{environment}: #{detail}" - error = Puppet::Error.new(msg) - error.set_backtrace(detail.backtrace) - raise error - end - def stale? @watched_files.values.detect { |file| file.changed? } end @@ -197,12 +144,52 @@ class Puppet::Resource::TypeCollection private - def find_fully_qualified(name, type) - send(type, name.sub(/^::/, '')) + # Return a list of all possible fully-qualified names that might be + # meant by the given name, in the context of namespaces. + def resolve_namespaces(namespaces, name) + name = name.downcase + if name =~ /^::/ + # name is explicitly fully qualified, so just return it, sans + # initial "::". + return [name.sub(/^::/, '')] + end + if name == "" + # The name "" has special meaning--it always refers to a "main" + # hostclass which contains all toplevel resources. + return [""] + end + + namespaces = [namespaces] unless namespaces.is_a?(Array) + namespaces = namespaces.collect { |ns| ns.downcase } + + result = [] + namespaces.each do |namespace| + ary = namespace.split("::") + + # Search each namespace nesting in innermost-to-outermost order. + while ary.length > 0 + result << "#{ary.join("::")}::#{name}" + ary.pop + end + + # Finally, search the toplevel namespace. + result << name + end + + return result.uniq end - def find_partially_qualified(namespace, name, type) - send(type, [namespace, name].join("::")) + # Resolve namespaces and find the given object. Autoload it if + # necessary. + def find_or_load(namespaces, name, type) + resolve_namespaces(namespaces, name).each do |fqname| + if result = send(type, fqname) || loader.try_load_fqname(type, fqname) + return result + end + end + + # Nothing found. + return nil end def munge_name(name) diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb index 945b1beb3..6d153b46d 100644 --- a/lib/puppet/simple_graph.rb +++ b/lib/puppet/simple_graph.rb @@ -7,123 +7,45 @@ require 'set' # A hopefully-faster graph class to replace the use of GRATR. class Puppet::SimpleGraph - # An internal class for handling a vertex's edges. - class VertexWrapper - attr_accessor :in, :out, :vertex - - # Remove all references to everything. - def clear - @adjacencies[:in].clear - @adjacencies[:out].clear - @vertex = nil - end - - def initialize(vertex) - @vertex = vertex - @adjacencies = {:in => {}, :out => {}} - end - - # Find adjacent vertices or edges. - def adjacent(options) - direction = options[:direction] || :out - options[:type] ||= :vertices - - return send(direction.to_s + "_edges") if options[:type] == :edges - - @adjacencies[direction].keys.reject { |vertex| @adjacencies[direction][vertex].empty? } - end - - # Add an edge to our list. - def add_edge(direction, edge) - opposite_adjacencies(direction, edge) << edge - end - - # Return all known edges. - def edges - in_edges + out_edges - end - - # Test whether we share an edge with a given vertex. - def has_edge?(direction, vertex) - return(vertex_adjacencies(direction, vertex).length > 0 ? true : false) - end - - # Create methods for returning the degree and edges. - [:in, :out].each do |direction| - # LAK:NOTE If you decide to create methods for directly - # testing the degree, you'll have to get the values and flatten - # the results -- you might have duplicate edges, which can give - # a false impression of what the degree is. That's just - # as expensive as just getting the edge list, so I've decided - # to only add this method. - define_method("#{direction}_edges") do - @adjacencies[direction].values.inject([]) { |total, adjacent| total += adjacent.to_a; total } - end - end - - # The other vertex in the edge. - def other_vertex(direction, edge) - case direction - when :in; edge.source - else - edge.target - end - end - - # Remove an edge from our list. Assumes that we've already checked - # that the edge is valid. - def remove_edge(direction, edge) - opposite_adjacencies(direction, edge).delete(edge) - end - - def to_s - vertex.to_s - end - - private - - # These methods exist so we don't need a Hash with a default proc. - - # Look up the adjacencies for a vertex at the other end of an - # edge. - def opposite_adjacencies(direction, edge) - opposite_vertex = other_vertex(direction, edge) - vertex_adjacencies(direction, opposite_vertex) - end - - # Look up the adjacencies for a given vertex. - def vertex_adjacencies(direction, vertex) - @adjacencies[direction][vertex] ||= Set.new - @adjacencies[direction][vertex] - end - end - + # + # All public methods of this class must maintain (assume ^ ensure) the following invariants, where "=~=" means + # equiv. up to order: + # + # @in_to.keys =~= @out_to.keys =~= all vertices + # @in_to.values.collect { |x| x.values }.flatten =~= @out_from.values.collect { |x| x.values }.flatten =~= all edges + # @in_to[v1][v2] =~= @out_from[v2][v1] =~= all edges from v1 to v2 + # @in_to [v].keys =~= vertices with edges leading to v + # @out_from[v].keys =~= vertices with edges leading from v + # no operation may shed reference loops (for gc) + # recursive operation must scale with the depth of the spanning trees, or better (e.g. no recursion over the set + # of all vertices, etc.) + # + # This class is intended to be used with DAGs. However, if the + # graph has a cycle, it will not cause non-termination of any of the + # algorithms. The topsort method detects and reports cycles. + # def initialize - @vertices = {} - @edges = [] + @in_to = {} + @out_from = {} + @upstream_from = {} + @downstream_from = {} end # Clear our graph. def clear - @vertices.each { |vertex, wrapper| wrapper.clear } - @vertices.clear - @edges.clear - end - - # Which resources a given resource depends upon. - def dependents(resource) - tree_from_vertex(resource).keys + @in_to.clear + @out_from.clear + @upstream_from.clear + @downstream_from.clear end # Which resources depend upon the given resource. def dependencies(resource) - # Cache the reversal graph, because it's somewhat expensive - # to create. - @reversal ||= reversal - # Strangely, it's significantly faster to search a reversed - # tree in the :out direction than to search a normal tree - # in the :in direction. - @reversal.tree_from_vertex(resource, :out).keys + vertex?(resource) ? upstream_from_vertex(resource).keys : [] + end + + def dependents(resource) + vertex?(resource) ? downstream_from_vertex(resource).keys : [] end # Whether our graph is directed. Always true. Used to produce dot files. @@ -133,8 +55,7 @@ class Puppet::SimpleGraph # Determine all of the leaf nodes below a given vertex. def leaves(vertex, direction = :out) - tree = tree_from_vertex(vertex, direction) - l = tree.keys.find_all { |c| adjacent(c, :direction => direction).empty? } + tree_from_vertex(vertex, direction).keys.find_all { |c| adjacent(c, :direction => direction).empty? } end # Collect all of the edges that the passed events match. Returns @@ -149,9 +70,7 @@ class Puppet::SimpleGraph # Get all of the edges that this vertex should forward events # to, which is the same thing as saying all edges directly below # This vertex in the graph. - adjacent(source, :direction => :out, :type => :edges).find_all do |edge| - edge.match?(event.name) - end + @out_from[source].values.flatten.find_all { |edge| edge.match?(event.name) } end # Return a reversed version of this graph. @@ -159,20 +78,50 @@ class Puppet::SimpleGraph result = self.class.new vertices.each { |vertex| result.add_vertex(vertex) } edges.each do |edge| - newedge = edge.class.new(edge.target, edge.source, edge.label) - result.add_edge(newedge) + result.add_edge edge.class.new(edge.target, edge.source, edge.label) end result end # Return the size of the graph. def size - @vertices.length + vertices.size end - # Return the graph as an array. def to_a - @vertices.keys + vertices + end + + # Provide a topological sort with cycle reporting + def topsort_with_cycles + degree = {} + zeros = [] + result = [] + + # Collect each of our vertices, with the number of in-edges each has. + vertices.each do |v| + edges = @in_to[v].dup + zeros << v if edges.empty? + degree[v] = edges + end + + # Iterate over each 0-degree vertex, decrementing the degree of + # each of its out-edges. + while v = zeros.pop + result << v + @out_from[v].each { |v2,es| + degree[v2].delete(v) + zeros << v2 if degree[v2].empty? + } + end + + # If we have any vertices left with non-zero in-degrees, then we've found a cycle. + if cycles = degree.values.reject { |ns| ns.empty? } and cycles.length > 0 + message = cycles.collect { |edges| '('+edges.collect { |e| e.to_s }.join(", ")+')' }.join(", ") + raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz" + end + + result end # Provide a topological sort. @@ -182,26 +131,24 @@ class Puppet::SimpleGraph result = [] # Collect each of our vertices, with the number of in-edges each has. - @vertices.each do |name, wrapper| - edges = wrapper.in_edges - zeros << wrapper if edges.length == 0 - degree[wrapper.vertex] = edges + vertices.each do |v| + edges = @in_to[v] + zeros << v if edges.empty? + degree[v] = edges.length end # Iterate over each 0-degree vertex, decrementing the degree of # each of its out-edges. - while wrapper = zeros.pop - result << wrapper.vertex - wrapper.out_edges.each do |edge| - degree[edge.target].delete(edge) - zeros << @vertices[edge.target] if degree[edge.target].length == 0 - end + while v = zeros.pop + result << v + @out_from[v].each { |v2,es| + zeros << v2 if (degree[v2] -= 1) == 0 + } end # If we have any vertices left with non-zero in-degrees, then we've found a cycle. - if cycles = degree.find_all { |vertex, edges| edges.length > 0 } and cycles.length > 0 - message = cycles.collect { |vertex, edges| edges.collect { |e| e.to_s }.join(", ") }.join(", ") - raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz" + if cycles = degree.values.reject { |ns| ns == 0 } and cycles.length > 0 + topsort_with_cycles end result @@ -209,103 +156,80 @@ class Puppet::SimpleGraph # Add a new vertex to the graph. def add_vertex(vertex) - @reversal = nil - return false if vertex?(vertex) - setup_vertex(vertex) - true # don't return the VertexWrapper instance. + @in_to[vertex] ||= {} + @out_from[vertex] ||= {} end # Remove a vertex from the graph. - def remove_vertex!(vertex) - return nil unless vertex?(vertex) - @vertices[vertex].edges.each { |edge| remove_edge!(edge) } - @edges -= @vertices[vertex].edges - @vertices[vertex].clear - @vertices.delete(vertex) + def remove_vertex!(v) + return unless vertex?(v) + @upstream_from.clear + @downstream_from.clear + (@in_to[v].values+@out_from[v].values).flatten.each { |e| remove_edge!(e) } + @in_to.delete(v) + @out_from.delete(v) end # Test whether a given vertex is in the graph. - def vertex?(vertex) - @vertices.include?(vertex) + def vertex?(v) + @in_to.include?(v) end # Return a list of all vertices. def vertices - @vertices.keys + @in_to.keys end # Add a new edge. The graph user has to create the edge instance, # since they have to specify what kind of edge it is. - def add_edge(source, target = nil, label = nil) - @reversal = nil - if target - edge = Puppet::Relationship.new(source, target, label) - else - edge = source - end - [edge.source, edge.target].each { |vertex| setup_vertex(vertex) unless vertex?(vertex) } - @vertices[edge.source].add_edge :out, edge - @vertices[edge.target].add_edge :in, edge - @edges << edge - true + def add_edge(e,*a) + return add_relationship(e,*a) unless a.empty? + @upstream_from.clear + @downstream_from.clear + add_vertex(e.source) + add_vertex(e.target) + @in_to[ e.target][e.source] ||= []; @in_to[ e.target][e.source] |= [e] + @out_from[e.source][e.target] ||= []; @out_from[e.source][e.target] |= [e] end - # Find a matching edge. Note that this only finds the first edge, - # not all of them or whatever. - def edge(source, target) - @edges.each_with_index { |test_edge, index| return test_edge if test_edge.source == source and test_edge.target == target } + def add_relationship(source, target, label = nil) + add_edge Puppet::Relationship.new(source, target, label) end - def edge_label(source, target) - return nil unless edge = edge(source, target) - edge.label + # Find all matching edges. + def edges_between(source, target) + (@out_from[source] || {})[target] || [] end # Is there an edge between the two vertices? def edge?(source, target) - return false unless vertex?(source) and vertex?(target) - - @vertices[source].has_edge?(:out, target) + vertex?(source) and vertex?(target) and @out_from[source][target] end def edges - @edges.dup + @in_to.values.collect { |x| x.values }.flatten end - # Remove an edge from our graph. - def remove_edge!(edge) - @vertices[edge.source].remove_edge(:out, edge) - @vertices[edge.target].remove_edge(:in, edge) - - @edges.delete(edge) - nil + def each_edge + @in_to.each { |t,ns| ns.each { |s,es| es.each { |e| yield e }}} end - # Find adjacent edges. - def adjacent(vertex, options = {}) - return [] unless wrapper = @vertices[vertex] - wrapper.adjacent(options) + # Remove an edge from our graph. + def remove_edge!(e) + if edge?(e.source,e.target) + @upstream_from.clear + @downstream_from.clear + @in_to [e.target].delete e.source if (@in_to [e.target][e.source] -= [e]).empty? + @out_from[e.source].delete e.target if (@out_from[e.source][e.target] -= [e]).empty? + end end - private - - # An internal method that skips the validation, so we don't have - # duplicate validation calls. - def setup_vertex(vertex) - @vertices[vertex] = VertexWrapper.new(vertex) + # Find adjacent edges. + def adjacent(v, options = {}) + return [] unless ns = (options[:direction] == :in) ? @in_to[v] : @out_from[v] + (options[:type] == :edges) ? ns.values.flatten : ns.keys end - - public - -# # For some reason, unconnected vertices do not show up in -# # this graph. -# def to_jpg(path, name) -# gv = vertices -# Dir.chdir(path) do -# induced_subgraph(gv).write_to_graphic_file('jpg', name) -# end -# end - + # Take container information from another graph and use it # to replace any container vertices with their respective leaves. # This creates direct relationships where there were previously @@ -318,16 +242,15 @@ class Puppet::SimpleGraph # to container leaves, but that would result in many more # relationships. stage_class = Puppet::Type.type(:stage) + whit_class = Puppet::Type.type(:whit) containers = other.topsort.find_all { |v| (v.is_a?(type) or v.is_a?(stage_class)) and vertex?(v) } containers.each do |container| # Get the list of children from the other graph. children = other.adjacent(container, :direction => :out) - # Just remove the container if it's empty. - if children.empty? - remove_vertex!(container) - next - end + # MQR TODO: Luke suggests that it should be possible to refactor the system so that + # container nodes are retained, thus obviating the need for the whit. + children = [whit_class.new(:name => container.name, :catalog => other)] if children.empty? # First create new edges for each of the :in edges [:in, :out].each do |dir| @@ -382,6 +305,26 @@ class Puppet::SimpleGraph predecessor end + def downstream_from_vertex(v) + return @downstream_from[v] if @downstream_from[v] + result = @downstream_from[v] = {} + @out_from[v].keys.each do |node| + result[node] = 1 + result.update(downstream_from_vertex(node)) + end + result + end + + def upstream_from_vertex(v) + return @upstream_from[v] if @upstream_from[v] + result = @upstream_from[v] = {} + @in_to[v].keys.each do |node| + result[node] = 1 + result.update(upstream_from_vertex(node)) + end + result + end + # LAK:FIXME This is just a paste of the GRATR code with slight modifications. # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an @@ -423,18 +366,6 @@ class Puppet::SimpleGraph system('dotty', dotfile) end - # Use +dot+ to create a graphical representation of the graph. Returns the - # filename of the graphics file. - def write_to_graphic_file (fmt='png', dotfile='graph') - src = dotfile + '.dot' - dot = dotfile + '.' + fmt - - File.open(src, 'w') {|f| f << self.to_dot << "\n"} - - system( "dot -T#{fmt} #{src} -o #{dot}" ) - dot - end - # Produce the graph files if requested. def write_graph(name) return unless Puppet[:graph] @@ -446,4 +377,73 @@ class Puppet::SimpleGraph f.puts to_dot("name" => name.to_s.capitalize) } end + + # This flag may be set to true to use the new YAML serialzation + # format (where @vertices is a simple list of vertices rather than a + # list of VertexWrapper objects). Deserialization supports both + # formats regardless of the setting of this flag. + class << self + attr_accessor :use_new_yaml_format + end + self.use_new_yaml_format = false + + # Stub class to allow graphs to be represented in YAML using the old + # (version 2.6) format. + class VertexWrapper + attr_reader :vertex, :adjacencies + def initialize(vertex, adjacencies) + @vertex = vertex + @adjacencies = adjacencies + end + end + + # instance_variable_get is used by Object.to_zaml to get instance + # variables. Override it so that we can simulate the presence of + # instance variables @edges and @vertices for serialization. + def instance_variable_get(v) + case v.to_s + when '@edges' then + edges + when '@vertices' then + if self.class.use_new_yaml_format + vertices + else + result = {} + vertices.each do |vertex| + adjacencies = {} + [:in, :out].each do |direction| + adjacencies[direction] = {} + adjacent(vertex, :direction => direction, :type => :edges).each do |edge| + other_vertex = direction == :in ? edge.source : edge.target + (adjacencies[direction][other_vertex] ||= Set.new).add(edge) + end + end + result[vertex] = Puppet::SimpleGraph::VertexWrapper.new(vertex, adjacencies) + end + result + end + else + super(v) + end + end + + def to_yaml_properties + other_vars = instance_variables.reject { |v| %w{@in_to @out_from @upstream_from @downstream_from}.include?(v) } + (other_vars + %w{@vertices @edges}).sort.uniq + end + + def yaml_initialize(tag, var) + initialize() + vertices = var.delete('vertices') + edges = var.delete('edges') + if vertices.is_a?(Hash) + # Support old (2.6) format + vertices = vertices.keys + end + vertices.each { |v| add_vertex(v) } + edges.each { |e| add_edge(e) } + var.each do |varname, value| + instance_variable_set("@#{varname}", value) + end + end end diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb index e4d06a039..2f6cae3f5 100644 --- a/lib/puppet/ssl/certificate_request.rb +++ b/lib/puppet/ssl/certificate_request.rb @@ -29,7 +29,7 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base # 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 certname, rather than the + # 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 diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index 63e6b922a..f3321bd29 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -147,21 +147,19 @@ class Puppet::SSLCertificates::CA # Create the root certificate. def mkrootcert - # Make the root cert's name the FQDN of the host running the CA. - name = Facter["hostname"].value + # 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( - + cert = Certificate.new( :name => name, :cert => @config[:cacert], :encrypt => @config[:capass], :key => @config[:cakey], :selfsign => true, :ttl => ttl, - :type => :ca ) @@ -241,19 +239,15 @@ class Puppet::SSLCertificates::CA f << "%04X" % (serial + 1) } - - newcert = Puppet::SSLCertificates.mkcert( - + 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) diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb index e6d1e0528..1d3091428 100644 --- a/lib/puppet/transaction/report.rb +++ b/lib/puppet/transaction/report.rb @@ -62,30 +62,49 @@ class Puppet::Transaction::Report host end - # Provide a summary of this report. + # Provide a human readable textual summary of this report. def summary + report = raw_summary + ret = "" + report.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |key| + ret += "#{Puppet::Util::Metric.labelize(key)}:\n" - @metrics.sort { |a,b| a[1].label <=> b[1].label }.each do |name, metric| - ret += "#{metric.label}:\n" - metric.values.sort { |a,b| + report[key].keys.sort { |a,b| # sort by label - if a[0] == :total + if a == :total 1 - elsif b[0] == :total + elsif b == :total -1 else - a[1] <=> b[1] + report[key][a].to_s <=> report[key][b].to_s end - }.each do |name, label, value| + }.each do |label| + value = report[key][label] next if value == 0 value = "%0.2f" % value if value.is_a?(Float) - ret += " %15s %s\n" % [label + ":", value] + ret += " %15s %s\n" % [Puppet::Util::Metric.labelize(label) + ":", value] end end ret end + # Provide a raw hash summary of this report. + def raw_summary + report = {} + + @metrics.each do |name, metric| + key = metric.name.to_s + report[key] = {} + metric.values.each do |name, label, value| + report[key][name.to_s] = value + end + report[key]["total"] = 0 unless key == "time" or report[key].include?("total") + end + (report["time"] ||= {})["last_run"] = Time.now.tv_sec + report + end + # Based on the contents of this report's metrics, compute a single number # that represents the report. The resulting number is a bitmask where # individual bits represent the presence of different metrics. @@ -103,7 +122,6 @@ class Puppet::Transaction::Report resource_statuses.each do |name, status| metrics[:total] += status.change_count if status.change_count end - add_metric(:changes, metrics) end @@ -124,7 +142,6 @@ class Puppet::Transaction::Report metrics[:total] = resource_statuses.length resource_statuses.each do |name, status| - Puppet::Resource::Status::STATES.each do |state| metrics[state] += 1 if status.send(state) end diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb index aace6a38a..29ec9a539 100644 --- a/lib/puppet/transaction/resource_harness.rb +++ b/lib/puppet/transaction/resource_harness.rb @@ -72,7 +72,7 @@ class Puppet::Transaction::ResourceHarness resource[param] = value audited << param else - resource.info "Storing newly-audited value #{current[param]} for #{param}" + resource.debug "Storing newly-audited value #{current[param]} for #{param}" cache(resource, param, current[param]) end end diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index c3855a400..1b6e7dcd7 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -410,13 +410,15 @@ class Type property = self.newattr(name) - 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 + 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 @@ -472,6 +474,12 @@ class Type 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) @@ -933,16 +941,16 @@ class Type 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:: + that for your schedule: - schedule { daily: - period => daily, - range => \"2-4\" - } + schedule { daily: + period => daily, + range => \"2-4\" + } - exec { \"/usr/bin/apt-get update\": - schedule => daily - } + 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." @@ -957,7 +965,7 @@ class Type the value, and any changes already get logged." validate do |list| - list = Array(list) + list = Array(list).collect {|p| p.to_sym} unless list == [:all] list.each do |param| next if @resource.class.validattr?(param) @@ -982,8 +990,8 @@ class Type end def properties_to_audit(list) - if list == :all - list = all_properties if list == :all + if !list.kind_of?(Array) && list.to_sym == :all + list = all_properties else list = Array(list).collect { |p| p.to_sym } end @@ -1020,40 +1028,40 @@ class Type newmetaparam(:alias) do desc "Creates an alias for the object. Puppet uses this internally when you - provide a symbolic name:: - - file { sshdconfig: - path => $operatingsystem ? { - solaris => \"/usr/local/etc/ssh/sshd_config\", - default => \"/etc/ssh/sshd_config\" - }, - source => \"...\" - } + provide a symbolic name: + + file { sshdconfig: + path => $operatingsystem ? { + solaris => \"/usr/local/etc/ssh/sshd_config\", + default => \"/etc/ssh/sshd_config\" + }, + source => \"...\" + } - service { sshd: - subscribe => file[sshdconfig] - } + service { sshd: + subscribe => File[sshdconfig] + } - When you use this feature, the parser sets ``sshdconfig`` as the name, + When you use this feature, the parser sets `sshdconfig` as the name, and the library sets that as an alias for the file so the dependency - lookup for ``sshd`` works. You can use this parameter yourself, + lookup for `sshd` works. You can use this parameter yourself, but note that only the library can use these aliases; for instance, - the following code will not work:: + the following code will not work: - file { \"/etc/ssh/sshd_config\": - owner => root, - group => root, - alias => sshdconfig - } + file { \"/etc/ssh/sshd_config\": + owner => root, + group => root, + alias => sshdconfig + } - file { sshdconfig: - mode => 644 - } + 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 `LanguageTutorial language tutorial`:trac: for more information. + See the [Language Tutorial](http://docs.puppetlabs.com/guides/language_tutorial.html) for more information. " @@ -1083,9 +1091,9 @@ class Type 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:: + host's configuration: - puppet agent --test --tags mytag + puppet agent --test --tags mytag This way, when you're testing a configuration you can run just the portion you're testing." @@ -1189,23 +1197,23 @@ class Type newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do desc "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:: + happen before the dependent object. For instance: - # Create the destination directory before you copy things down - file { \"/usr/local/scripts\": - ensure => directory - } + # 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\"] - } + 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:: + of resources, enclosed in square brackets: - require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ] + 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 @@ -1219,10 +1227,10 @@ class Type 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 + 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 + `exec` code, so that you would always be running againts the most recent version. " end @@ -1230,20 +1238,20 @@ class Type newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do desc "One or more objects that this object depends on. Changes in the subscribed to objects result in the dependent objects being - refreshed (e.g., a service will get restarted). For instance:: - - class nagios { - file { \"/etc/nagios/nagios.conf\": - source => \"puppet://server/module/nagios.conf\", - alias => nagconf # just to make things easier for me - } - service { nagios: - ensure => running, - subscribe => File[nagconf] + refreshed (e.g., a service will get restarted). For instance: + + class nagios { + file { \"/etc/nagios/nagios.conf\": + source => \"puppet://server/module/nagios.conf\", + alias => nagconf # just to make things easier for me + } + service { nagios: + ensure => running, + subscribe => File[nagconf] + } } - } - Currently the ``exec``, ``mount`` and ``service`` type support + Currently the `exec`, `mount` and `service` type support refreshing. " end @@ -1251,18 +1259,18 @@ class Type newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do desc %{This parameter is the opposite of **require** -- it guarantees that the specified object is applied later than the specifying - object:: + object: - file { "/var/nagios/configuration": - source => "...", - recurse => true, - before => Exec["nagios-rebuid"] - } + file { "/var/nagios/configuration": + source => "...", + recurse => true, + before => Exec["nagios-rebuid"] + } - exec { "nagios-rebuild": - command => "/usr/bin/make", - cwd => "/var/nagios/configuration" - } + 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.} @@ -1270,16 +1278,16 @@ class Type newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do desc %{This parameter is the opposite of **subscribe** -- it sends events - to the specified object:: + to the specified object: - file { "/etc/sshd_config": - source => "....", - notify => Service[sshd] - } + file { "/etc/sshd_config": + source => "....", + notify => Service[sshd] + } - service { sshd: - ensure => running - } + service { sshd: + ensure => running + } This will restart the sshd service if the sshd config file changes.} end @@ -1293,24 +1301,24 @@ class Type By default, all classes get directly added to the 'main' stage. You can create new stages as resources: - stage { [pre, post]: } + stage { [pre, post]: } To order stages, use standard relationships: - stage { pre: before => Stage[main] } + stage { pre: before => Stage[main] } Or use the new relationship syntax: - Stage[pre] -> Stage[main] -> Stage[post] + Stage[pre] -> Stage[main] -> Stage[post] Then use the new class parameters to specify a stage: - class { foo: stage => pre } + class { foo: stage => pre } Stages can only be set on classes, not individual resources. This will - fail:: + fail: - file { '/foo': stage => pre, ensure => file } + file { '/foo': stage => pre, ensure => file } } end diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb index 7fcfdd7a3..d29bda648 100644 --- a/lib/puppet/type/augeas.rb +++ b/lib/puppet/type/augeas.rb @@ -28,27 +28,28 @@ Puppet::Type.newtype(:augeas) do via the augeas tool. Requires: - - augeas to be installed (http://www.augeas.net) - - ruby-augeas bindings - Sample usage with a string:: + - augeas to be installed (http://www.augeas.net) + - ruby-augeas bindings - augeas{\"test1\" : - context => \"/files/etc/sysconfig/firstboot\", - changes => \"set RUN_FIRSTBOOT YES\", - onlyif => \"match other_value size > 0\", - } + Sample usage with a string: - Sample usage with an array and custom lenses:: + augeas{\"test1\" : + context => \"/files/etc/sysconfig/firstboot\", + changes => \"set RUN_FIRSTBOOT YES\", + onlyif => \"match other_value size > 0\", + } - augeas{\"jboss_conf\": - 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\", - } + 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\" + ], + load_path => \"$/usr/share/jbossas/lenses\", + } " @@ -71,23 +72,23 @@ Puppet::Type.newtype(:augeas) do 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] - - 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']" + 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] + + 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']" defaultto "" end @@ -95,16 +96,14 @@ Puppet::Type.newtype(:augeas) do 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:: + Commands supported are: - set [PATH] [VALUE] Sets the value VALUE at loction PATH - rm [PATH] Removes the node at location PATH - remove [PATH] Synonym for rm - clear [PATH] Keeps the node at PATH, but removes the value. - ins [LABEL] [WHERE] [PATH] - Inserts an empty node LABEL either [WHERE={before|after}] PATH. - insert [LABEL] [WHERE] [PATH] - Synonym for ins + set [PATH] [VALUE] Sets the value VALUE at loction PATH + rm [PATH] Removes the node at location PATH + remove [PATH] Synonym for rm + clear [PATH] Keeps the node at PATH, but removes the value. + ins [LABEL] [WHERE] [PATH] Inserts an empty node LABEL either [WHERE={before|after}] PATH. + insert [LABEL] [WHERE] [PATH] Synonym for ins If the parameter 'context' is set that value is prepended to PATH" end @@ -136,11 +135,11 @@ Puppet::Type.newtype(:augeas) do 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. Only that file will be loaded, which greatly speeds up execution of the type" 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`. When this parameter is set, you must also set the lens parameter to indicate which lens to use." end validate do diff --git a/lib/puppet/type/computer.rb b/lib/puppet/type/computer.rb index 86a30be27..89a0692bf 100644 --- a/lib/puppet/type/computer.rb +++ b/lib/puppet/type/computer.rb @@ -10,7 +10,7 @@ Puppet::Type.newtype(:computer) do This provider only manages Computer objects in the local directory service domain, not in remote directories. - If you wish to manage /etc/hosts on Mac OS X, then simply use the host + 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 @@ -31,7 +31,7 @@ Puppet::Type.newtype(:computer) do 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`` + `present` to ensure the computer record exists. Set it to `absent` to delete any computer records with this name" newvalue(:present) do provider.create diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index b3f5e608d..76399d693 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -15,32 +15,32 @@ Puppet::Type.newtype(:cron) do 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 - } - - Note that all cron values can be specified as an array of values:: - - cron { logrotate: - command => \"/usr/sbin/logrotate\", - user => root, - hour => [2, 4] - } - - Or using ranges, or the step syntax ``*/2`` (although there's no guarantee that - your ``cron`` daemon supports it):: - - cron { logrotate: - command => \"/usr/sbin/logrotate\", - user => root, - hour => ['2-4'], - minute => '*/10' - } + Example: + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => 2, + minute => 0 + } + + Note that all cron values can be specified as an array of values: + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => [2, 4] + } + + Or using ranges, or the step syntax `*/2` (although there's no guarantee that + your `cron` daemon supports it): + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => ['2-4'], + minute => '*/10' + } " ensurable @@ -169,7 +169,7 @@ Puppet::Type.newtype(:cron) do end if value == "*" - return value + return :absent end return value unless self.class.boundaries @@ -206,7 +206,7 @@ Puppet::Type.newtype(:cron) do 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 + All cron parameters support `absent` as a value; this will remove any existing values for that field." def retrieve @@ -230,7 +230,7 @@ Puppet::Type.newtype(:cron) do end newproperty(:special) do - desc "Special schedules only supported on FreeBSD." + desc "Special schedules" def specials %w{reboot yearly annually monthly weekly daily midnight hourly} @@ -293,7 +293,7 @@ Puppet::Type.newtype(:cron) do 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``." + 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" diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index bfeaaad34..606888c75 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -6,51 +6,51 @@ module Puppet @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 + commands is to use the checks like `creates` to avoid running the command unless some condition is met. - Note also that you can restrict an ``exec`` to only run when it receives - events by using the ``refreshonly`` parameter; this is a useful way to + Note also 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. - It is worth noting that ``exec`` is special, in that it is not - currently considered an error to have multiple ``exec`` instances + It is worth noting that `exec` is special, in that it is not + currently considered an error to have multiple `exec` instances with the same name. This was done purely because it had to be this way in order to get certain functionality, but it complicates things. - In particular, you will not be able to use ``exec`` instances that + In particular, you will not be able to use `exec` instances that share their commands with other instances as a dependency, since Puppet has no way of knowing which instance you mean. - For example:: + For example: - # defined in the production class - exec { \"make\": - cwd => \"/prod/build/dir\", - path => \"/usr/bin:/usr/sbin:/bin\" - } + # defined in the production class + exec { \"make\": + cwd => \"/prod/build/dir\", + path => \"/usr/bin:/usr/sbin:/bin\" + } - . etc. . + . etc. . - # defined in the test class - exec { \"make\": - cwd => \"/test/build/dir\", - path => \"/usr/bin:/usr/sbin:/bin\" - } + # defined in the test class + exec { \"make\": + cwd => \"/test/build/dir\", + path => \"/usr/bin:/usr/sbin:/bin\" + } Any other type would throw an error, complaining that you had the same instance being managed in multiple places, but these are - obviously different images, so ``exec`` had to be treated specially. + obviously different images, so `exec` had to be treated specially. It is recommended to avoid duplicate names whenever possible. - Note 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). + Note 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 + 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`` + 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 + 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." @@ -159,9 +159,9 @@ module Puppet 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 + 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." + any output is logged at the `err` log level." end newparam(:path) do @@ -223,7 +223,7 @@ module Puppet newparam(:logoutput) do desc "Whether to log output. Defaults to logging output at the - loglevel for the ``exec`` resource. Use *on_failure* to only + 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." @@ -253,7 +253,7 @@ module Puppet 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 + the `path` attribute. Multiple environment variables should be specified as an array." validate do |values| @@ -330,22 +330,22 @@ module Puppet desc "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\" - } - - # Rebuild the database, but only when the file changes - exec { newaliases: - path => [\"/usr/bin\", \"/usr/sbin\"], - subscribe => File[\"/etc/aliases\"], - refreshonly => true - } + other object; it is useful for triggering an action: + + # Pull down the main aliases file + 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\"], + 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``." + Note that only `subscribe` and `notify` can trigger actions, not `require`, + so it only makes sense to use `refreshonly` with `subscribe` or `notify`." newvalues(:true, :false) @@ -364,13 +364,13 @@ module Puppet newcheck(:creates) do desc "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:: + if the specified file does not exist: - exec { \"tar xf /my/tar/file.tar\": - cwd => \"/var/tmp\", - creates => \"/var/tmp/myfile\", - path => [\"/usr/bin\", \"/usr/sbin\"] - } + exec { \"tar xf /my/tar/file.tar\": + cwd => \"/var/tmp\", + creates => \"/var/tmp/myfile\", + path => [\"/usr/bin\", \"/usr/sbin\"] + } " @@ -396,16 +396,16 @@ module Puppet end newcheck(:unless) do - desc "If this parameter is set, then this ``exec`` will run unless - the command returns 0. For example:: + desc "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. + 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. @@ -433,22 +433,22 @@ module Puppet end newcheck(:onlyif) do - desc "If this parameter is set, then this ``exec`` will only run if - the command returns 0. For example:: + desc "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. + 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, eg:: + 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. " @@ -553,13 +553,7 @@ module Puppet if self[:path] if Puppet.features.posix? and !File.exists?(exe) withenv :PATH => self[:path].join(File::PATH_SEPARATOR) do - path = %x{which #{exe}}.chomp - if path == "" - raise ArgumentError, - "Could not find command '#{exe}'" - else - exe = path - end + exe = which(exe) || raise(ArgumentError,"Could not find command '#{exe}'") end elsif Puppet.features.microsoft_windows? and !File.exists?(exe) self[:path].each do |path| @@ -683,4 +677,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 71f2756bc..f35a26408 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -16,7 +16,7 @@ Puppet::Type.newtype(:file) do @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 + 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 @@ -61,33 +61,33 @@ Puppet::Type.newtype(:file) do 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 + 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 + 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 + backup. Setting `backup => false` disables all backups of the file in question. - Puppet automatically creates a local filebucket named ``puppet`` and + 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:: + you must specify one in your configuration - filebucket { main: - server => puppet - } + filebucket { main: + server => puppet + } - The ``puppet master`` daemon creates a filebucket by default, + 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:: + configuration, you can use it in any file - file { \"/my/file\": - source => \"/path/in/nfs/or/something\", - backup => main - } + file { \"/my/file\": + source => \"/path/in/nfs/or/something\", + backup => main + } This will back the file up to the central server. @@ -192,9 +192,9 @@ Puppet::Type.newtype(:file) do 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]*``. + engine, so shell metacharacters are fully supported, e.g. `[a-z]*`. Matches that would descend into the directory structure are ignored, - e.g., ``*/*``." + e.g., `*/*`." validate do |value| unless value.is_a?(Array) or value.is_a?(String) or value == false @@ -205,10 +205,10 @@ Puppet::Type.newtype(:file) do 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 + `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." newvalues(:follow, :manage) @@ -223,7 +223,7 @@ Puppet::Type.newtype(:file) do 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 + Note that when using `purge` with `source`, Puppet will purge any files that are not on the remote system." defaultto :false @@ -234,7 +234,7 @@ Puppet::Type.newtype(:file) do 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``, + 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." diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb index 74b380f55..b8f30a9c7 100755 --- a/lib/puppet/type/file/content.rb +++ b/lib/puppet/type/file/content.rb @@ -161,11 +161,17 @@ module Puppet } end + def self.standalone? + Puppet.settings[:name] == "apply" + end + def each_chunk_from(source_or_content) if source_or_content.is_a?(String) yield source_or_content elsif source_or_content.nil? yield read_file_from_filebucket + elsif self.class.standalone? + yield source_or_content.content elsif source_or_content.local? chunk_file_from_disk(source_or_content) { |chunk| yield chunk } else @@ -184,7 +190,7 @@ module Puppet end def chunk_file_from_source(source_or_content) - request = Puppet::Indirector::Request.new(:file_content, :find, source_or_content.full_path) + request = Puppet::Indirector::Request.new(:file_content, :find, source_or_content.full_path.sub(/^\//,'')) connection = Puppet::Network::HttpPool.http_instance(source_or_content.server, source_or_content.port) connection.request_get(indirection2uri(request), add_accept_encoding({"Accept" => "raw"})) do |response| case response.code diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb index c74a1d47a..967e06aee 100755 --- a/lib/puppet/type/file/ensure.rb +++ b/lib/puppet/type/file/ensure.rb @@ -3,27 +3,27 @@ module Puppet require 'etc' desc "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 + 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 be considered to be a symlink. - For instance, the following text creates a link:: + For instance, the following text creates a link: - # Useful on solaris - file { \"/etc/inetd.conf\": - ensure => \"/etc/inet/inetd.conf\" - } + # Useful on solaris + file { \"/etc/inetd.conf\": + ensure => \"/etc/inet/inetd.conf\" + } - You can make relative links:: + You can make relative links: - # Useful on solaris - file { \"/etc/inetd.conf\": - ensure => \"inet/inetd.conf\" - } + # Useful on solaris + file { \"/etc/inetd.conf\": + ensure => \"inet/inetd.conf\" + } If you need to make a relative link to a file named the same - as one of the valid values, you must prefix it with ``./`` or + as one of the valid values, you must prefix it with `./` or something similar. You can also make recursive symlinks, which will create a diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb index 9abf56d26..1ce56c843 100755 --- a/lib/puppet/type/file/mode.rb +++ b/lib/puppet/type/file/mode.rb @@ -13,14 +13,14 @@ module Puppet 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.:: + world-readable by setting e.g.: - file { '/some/dir': - mode => 644, - recurse => true, - } + file { '/some/dir': + mode => 644, + recurse => true, + } - In this case all of the files underneath ``/some/dir`` will have + In this case all of the files underneath `/some/dir` will have mode 644, and all of the directories will have mode 755." @event = :file_changed diff --git a/lib/puppet/type/file/selcontext.rb b/lib/puppet/type/file/selcontext.rb index edcfb83b2..a33c6a000 100644 --- a/lib/puppet/type/file/selcontext.rb +++ b/lib/puppet/type/file/selcontext.rb @@ -56,7 +56,7 @@ module Puppet Puppet::Type.type(:file).newproperty(:seluser, :parent => Puppet::SELFileContext) do desc "What the SELinux user component of the context of the file should be. - Any valid SELinux user component is accepted. For example ``user_u``. + Any valid SELinux user component is accepted. For example `user_u`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled." @@ -67,7 +67,7 @@ module Puppet Puppet::Type.type(:file).newproperty(:selrole, :parent => Puppet::SELFileContext) do desc "What the SELinux role component of the context of the file should be. - Any valid SELinux role component is accepted. For example ``role_r``. + Any valid SELinux role component is accepted. For example `role_r`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled." @@ -78,7 +78,7 @@ module Puppet Puppet::Type.type(:file).newproperty(:seltype, :parent => Puppet::SELFileContext) do desc "What the SELinux type component of the context of the file should be. - Any valid SELinux type component is accepted. For example ``tmp_t``. + Any valid SELinux type component is accepted. For example `tmp_t`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled." @@ -89,8 +89,8 @@ module Puppet Puppet::Type.type(:file).newproperty(:selrange, :parent => Puppet::SELFileContext) do desc "What the SELinux range component of the context of the file should be. - Any valid SELinux range component is accepted. For example ``s0`` or - ``SystemHigh``. If not specified it defaults to the value returned by + Any valid SELinux range component is accepted. For example `s0` or + `SystemHigh`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled and that have support for MCS (Multi-Category Security)." diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 2eaf4a33f..7d03de2b0 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -12,7 +12,7 @@ module Puppet include Puppet::Util::Diff attr_accessor :source, :local - desc "Copy a file over the current file. Uses ``checksum`` to + desc "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*. @@ -20,47 +20,47 @@ module Puppet 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:: + sytems. For instance: - class sendmail { - file { \"/etc/mail/sendmail.cf\": - source => \"puppet://server/modules/module_name/sendmail.cf\" + class sendmail { + 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`` + 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 + 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 + `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 `FileServingConfiguration fileserver configuration documentation`:trac: for information on how to configure + See the [fileserver configuration documentation](http://projects.puppetlabs.com/projects/puppet/wiki/File_Serving_Configuration) 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\": - source => [ - \"/modules/nfs/files/file.$host\", - \"/modules/nfs/files/file.$operatingsystem\", - \"/modules/nfs/files/file\" - ] - } + what amount to search paths for files: + + file { \"/path/to/my/file\": + source => [ + \"/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. + You cannot currently copy links using this mechanism; set `links` + to `follow` if any remote sources are links. " validate do |sources| @@ -94,6 +94,16 @@ module Puppet metadata && metadata.checksum end + # Look up (if necessary) and return remote content. + cached_attr(:content) do + raise Puppet::DevError, "No source for content was stored with the metadata" unless metadata.source + + unless tmp = Puppet::FileServing::Content.find(metadata.source) + fail "Could not find any content at %s" % metadata.source + end + 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 diff --git a/lib/puppet/type/filebucket.rb b/lib/puppet/type/filebucket.rb index 65ff88411..7fd2ef46b 100755 --- a/lib/puppet/type/filebucket.rb +++ b/lib/puppet/type/filebucket.rb @@ -16,13 +16,13 @@ module Puppet undo transactions. You will normally want to define a single filebucket for your - whole network and then use that as the default backup location:: + whole network and then use that as the default backup location: - # Define the bucket - filebucket { main: server => puppet } + # Define the bucket + filebucket { main: server => puppet } - # Specify it as the default target - File { backup => main } + # Specify it as the default target + File { backup => main } Puppetmaster servers create a filebucket by default, so this will work in a default configuration." @@ -92,4 +92,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb index 9f26d2243..cde1cfd65 100755 --- a/lib/puppet/type/group.rb +++ b/lib/puppet/type/group.rb @@ -89,7 +89,7 @@ module Puppet newparam(:allowdupe, :boolean => true) do desc "Whether to allow duplicate GIDs. This option does not work on - FreeBSD (contract to the ``pw`` man page)." + FreeBSD (contract to the `pw` man page)." newvalues(:true, :false) @@ -97,4 +97,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index 929542d7c..1af74d886 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -5,19 +5,17 @@ module Puppet 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" + 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 end newproperty(:host_aliases) do - desc 'Any aliases the host might have. Multiple values must be - specified as an array. Note that this property is not the same as - the "alias" metaparam; use this property to add aliases to a host - on disk, and "alias" to aliases for use in your Puppet scripts.' + desc "Any aliases the host might have. Multiple values must be + specified as an array." def insync?(is) is == @should @@ -28,21 +26,6 @@ module Puppet currentvalue.join(" ") end - def retrieve - is = super - case is - when String - is = is.split(/\s*,\s*/) - when Symbol - is = [is] - when Array - # nothing - else - raise Puppet::DevError, "Invalid @is type #{is.class}" - end - is - end - # We actually want to return the whole array here, not just the first # value. def should @@ -63,9 +46,14 @@ module Puppet 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" + end + newproperty(:target) do desc "The file in which to store service information. Only used by those providers that write to disk." @@ -94,8 +82,7 @@ module Puppet end @doc = "Installs and manages host entries. For most systems, these - entries will just be in ``/etc/hosts``, but some systems (notably OS X) + 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/k5login.rb b/lib/puppet/type/k5login.rb index 850e37733..a343e9e5c 100644 --- a/lib/puppet/type/k5login.rb +++ b/lib/puppet/type/k5login.rb @@ -3,15 +3,15 @@ # 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 + @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." 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." end # The path/name of the k5login file diff --git a/lib/puppet/type/macauthorization.rb b/lib/puppet/type/macauthorization.rb index 9b17c279d..ef6fbb6c1 100644 --- a/lib/puppet/type/macauthorization.rb +++ b/lib/puppet/type/macauthorization.rb @@ -1,8 +1,7 @@ Puppet::Type.newtype(:macauthorization) do @doc = "Manage the Mac OS X authorization database. - See: - http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html for more information." + See the [Apple developer site](http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html) for more information." ensurable diff --git a/lib/puppet/type/mailalias.rb b/lib/puppet/type/mailalias.rb index 5534fdf25..ce7ca790b 100755 --- a/lib/puppet/type/mailalias.rb +++ b/lib/puppet/type/mailalias.rb @@ -46,4 +46,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/maillist.rb b/lib/puppet/type/maillist.rb index 7ac0e4e4f..732fbf09f 100755 --- a/lib/puppet/type/maillist.rb +++ b/lib/puppet/type/maillist.rb @@ -60,4 +60,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/mcx.rb b/lib/puppet/type/mcx.rb index e56b11938..4f0a6c3c5 100644 --- a/lib/puppet/type/mcx.rb +++ b/lib/puppet/type/mcx.rb @@ -21,8 +21,6 @@ Puppet::Type.newtype(:mcx) do @doc = "MCX object management using DirectoryService on OS X. -Original Author: Jeff McCune <mccune.jeff@gmail.com> - The default provider of this type merely manages the XML plist as reported by the dscl -mcxexport command. This is similar to the content property of the file type in Puppet. @@ -51,13 +49,13 @@ to other machines. newparam(:name) do desc "The name of the resource being managed. - The default naming convention follows Directory Service paths:: + The default naming convention follows Directory Service paths: - /Computers/localhost - /Groups/admin - /Users/localadmin + /Computers/localhost + /Groups/admin + /Users/localadmin - The ds_type and ds_name type parameters are not necessary if the + The `ds_type` and `ds_name` type parameters are not necessary if the default naming convention is followed." isnamevar end @@ -80,8 +78,10 @@ to other machines. newproperty(:content, :required_features => :manages_content) do desc "The XML Plist. 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." + + 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 diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb index 6ee5dd174..e8c6b3290 100755 --- a/lib/puppet/type/mount.rb +++ b/lib/puppet/type/mount.rb @@ -5,8 +5,8 @@ module Puppet 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``." + 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] @@ -15,10 +15,10 @@ module Puppet # 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 - 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 + `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 + 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" newvalue(:defined) do @@ -149,7 +149,7 @@ module Puppet 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``." + Valid values are `1` or `0`. or `2` on FreeBSD, Default is `0`." if Facter["operatingsystem"].value == "FreeBSD" newvalue(%r{(0|1|2)}) @@ -183,7 +183,7 @@ module Puppet end newparam(:path) do - desc "The deprecated name for the mount point. Please use ``name`` now." + desc "The deprecated name for the mount point. Please use `name` now." def value=(value) warning "'path' is deprecated for mounts. Please use 'name'." @@ -193,7 +193,7 @@ module Puppet end newparam(:remounts) do - desc "Whether the mount can be remounted ``mount -o remount``. If + 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." @@ -210,7 +210,7 @@ module Puppet def refresh # Only remount if we're supposed to be mounted. - provider.remount if self.should(:fstype) != "swap" and provider.mounted? + provider.remount if self.should(:fstype) != "swap" and self.should(:ensure) == :mounted end def value(name) @@ -222,4 +222,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/notify.rb b/lib/puppet/type/notify.rb index 97935e270..a6ec1dc8b 100644 --- a/lib/puppet/type/notify.rb +++ b/lib/puppet/type/notify.rb @@ -42,4 +42,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index f25464db5..51a866332 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -8,12 +8,12 @@ module Puppet @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 + 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 + 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." @@ -22,7 +22,7 @@ module Puppet 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 + 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 @@ -104,7 +104,6 @@ module Puppet end end - defaultto :installed # Override the parent method, because we've got all kinds of @@ -181,35 +180,35 @@ module Puppet 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 - } - - . 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, - require => Package[openssl] - } + 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 + } + + . 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, + require => Package[openssl] + } " isnamevar @@ -228,7 +227,7 @@ module Puppet end newparam(:type) do - desc "Deprecated form of ``provider``." + desc "Deprecated form of `provider`." munge do |value| warning "'type' is deprecated; use 'provider' instead" @@ -243,7 +242,7 @@ module Puppet 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." + or it should be in `/var/sadm/install/admin`." end newparam(:responsefile) do @@ -320,4 +319,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/resources.rb b/lib/puppet/type/resources.rb index 34382e067..ae41b883b 100644 --- a/lib/puppet/type/resources.rb +++ b/lib/puppet/type/resources.rb @@ -1,12 +1,9 @@ -# Created by Luke Kanies on 2006-12-12. -# Copyright (c) 2006. All rights reserved. - require 'puppet' Puppet::Type.newtype(:resources) do @doc = "This is a metatype that can manage other resource types. Any metaparams specified here will be passed on to any generated resources, - so you can purge umanaged resources but set ``noop`` to true so the + so you can purge umanaged resources but set `noop` to true so the purging is only logged and does not actually happen." @@ -132,4 +129,3 @@ Puppet::Type.newtype(:resources) do %w{root nobody bin noaccess daemon sys} end end - diff --git a/lib/puppet/type/schedule.rb b/lib/puppet/type/schedule.rb index bedf1e536..82f17e533 100755 --- a/lib/puppet/type/schedule.rb +++ b/lib/puppet/type/schedule.rb @@ -16,7 +16,7 @@ module Puppet Thus, it behooves you 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:: + the hours of two and 4 AM, then you would use this schedule: schedule { maint: range => \"2 - 4\", @@ -33,7 +33,7 @@ module Puppet 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:: + with the following attributes: schedule { puppet: period => hourly, @@ -45,11 +45,11 @@ module Puppet newparam(:name) do desc "The name of the schedule. This name is used to retrieve the - schedule when assigning it to an object:: + schedule when assigning it to an object: schedule { daily: period => daily, - range => [2, 4] + range => \"2 - 4\", } exec { \"/usr/bin/apt-get update\": @@ -65,7 +65,7 @@ module Puppet 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:: + For instance: schedule { maintenance: range => \"1:30 - 4:30\" @@ -196,17 +196,17 @@ module Puppet 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:: + specified number of times. Take this schedule: - schedule { veryoften: - period => hourly, - repeat => 6 - } + schedule { veryoften: + period => hourly, + repeat => 6 + } This can cause Puppet to apply that resource up to every 10 minutes. @@ -215,7 +215,7 @@ module Puppet 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 + See the `periodmatch` attribute for tuning whether to match times by their distance apart or by their specific value." newvalues(:hourly, :daily, :weekly, :monthly, :never) @@ -307,10 +307,10 @@ module Puppet Puppet.debug "Creating default schedules" result << self.new( - + :name => "puppet", :period => :hourly, - + :repeat => "2" ) @@ -318,9 +318,7 @@ module Puppet @parameters.find { |p| p.name == :period }.value_collection.values.each { |value| result << self.new( - :name => value.to_s, - :period => value ) } @@ -349,4 +347,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/selboolean.rb b/lib/puppet/type/selboolean.rb index cf873e987..204b89056 100644 --- a/lib/puppet/type/selboolean.rb +++ b/lib/puppet/type/selboolean.rb @@ -1,11 +1,7 @@ -# -# Simple module for manageing SELinux booleans -# - module Puppet newtype(:selboolean) do @doc = "Manages SELinux booleans on systems with SELinux support. The supported booleans - are any of the ones found in /selinux/booleans/." + are any of the ones found in `/selinux/booleans/`." newparam(:name) do desc "The name of the SELinux boolean to be managed." @@ -20,7 +16,7 @@ module Puppet newparam(:persistent) do desc "If set true, SELinux booleans will be written to disk and persist accross reboots. - The default is ``false``." + The default is `false`." defaultto :false newvalues(:true, :false) @@ -28,4 +24,3 @@ module Puppet end end - diff --git a/lib/puppet/type/selmodule.rb b/lib/puppet/type/selmodule.rb index 240d6e6d1..60be8a855 100644 --- a/lib/puppet/type/selmodule.rb +++ b/lib/puppet/type/selmodule.rb @@ -18,7 +18,7 @@ Puppet::Type.newtype(:selmodule) do newparam(:selmoduledir) do desc "The directory to look for the compiled pp module file in. - Currently defaults to /usr/share/selinux/targeted. If selmodulepath + 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." @@ -34,9 +34,9 @@ Puppet::Type.newtype(:selmodule) do newproperty(:syncversion) do - desc "If set to ``true``, the policy will be reloaded if the + 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 + 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) @@ -51,4 +51,3 @@ Puppet::Type.newtype(:selmodule) do end end end - diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 8f5c6ee37..786a50448 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -17,10 +17,10 @@ module Puppet can provide the better behaviour you will get. Or, you can just use a platform that has very good service support. - Note that if a ``service`` receives an event from another resource, + 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 a special command - for restarting with the ``restart`` attribute." + for restarting with the `restart` attribute." feature :refreshable, "The provider can restart the service.", :methods => [:restart] @@ -83,7 +83,7 @@ module Puppet 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 + used to start the service if no `start` parameter is provided." end @@ -94,12 +94,14 @@ module Puppet not support any kind of status command; thus, you must specify manually whether the service you are running has such a command (or you can specify a specific command using the - ``status`` parameter). + `status` parameter). If you do not specify anything, then the service name will be looked for in the process table." newvalues(:true, :false) + + defaultto :true end newparam(:name) do desc "The name of the service to run. This name is used to find @@ -140,7 +142,7 @@ module Puppet end newparam(:start) do desc "Specify a *start* command manually. Most service subsystems - support a ``start`` command, so this will not need to be + support a `start` command, so this will not need to be specified." end newparam(:status) do @@ -156,14 +158,14 @@ module Puppet 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." + 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` option. Otherwise, + the init script's `stop` and `start` methods are used." newvalues(:true, :false) end diff --git a/lib/puppet/type/ssh_authorized_key.rb b/lib/puppet/type/ssh_authorized_key.rb index 2bfa87b0f..e3320140e 100644 --- a/lib/puppet/type/ssh_authorized_key.rb +++ b/lib/puppet/type/ssh_authorized_key.rb @@ -34,8 +34,8 @@ module Puppet newproperty(:target) do desc "The absolute filename in which to store the SSH key. This property is optional and should only be used in cases where keys - are stored in a non-standard location (ie not in - ~user/.ssh/authorized_keys)." + are stored in a non-standard location (i.e.` not in + `~user/.ssh/authorized_keys`)." defaultto :absent @@ -96,4 +96,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb index e1adc7173..b7a1b8a8d 100755 --- a/lib/puppet/type/sshkey.rb +++ b/lib/puppet/type/sshkey.rb @@ -1,8 +1,8 @@ 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, and - it cannot manage user authorized keys yet." + only knows how to install keys into `/etc/ssh/ssh_known_hosts`. See + the `ssh_authorized_key` type to manage authorized keys." ensurable @@ -23,9 +23,7 @@ module Puppet # 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. Note that this property is not the same as - the "alias" metaparam; use this property to add aliases to a host - on disk, and "alias" to aliases for use in your Puppet scripts.' + specified as an array.' attr_accessor :meta @@ -56,7 +54,7 @@ module Puppet newproperty(:target) do desc "The file in which to store the ssh key. Only used by - the ``parsed`` provider." + the `parsed` provider." defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile) @resource.class.defaultprovider.default_target @@ -67,4 +65,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/stage.rb b/lib/puppet/type/stage.rb index d22cd7b70..0736dc4b9 100644 --- a/lib/puppet/type/stage.rb +++ b/lib/puppet/type/stage.rb @@ -1,11 +1,12 @@ 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 } + be specified on resources: + + class { foo: stage => pre } - And you must manually control stage order:: + And you must manually control stage order: - stage { pre: before => Stage[main] } + stage { pre: before => Stage[main] } You automatically get a 'main' stage created, and by default all resources get inserted into that stage. diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb index a6605211e..93a7e96cf 100755 --- a/lib/puppet/type/tidy.rb +++ b/lib/puppet/type/tidy.rb @@ -1,11 +1,12 @@ 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 + 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 @@ -47,7 +48,7 @@ Puppet::Type.newtype(:tidy) do at least one of the patterns specified. Multiple patterns can be specified using an array. - Example:: + Example: tidy { \"/tmp\": age => \"1w\", @@ -55,7 +56,7 @@ Puppet::Type.newtype(:tidy) do matches => [ \"[0-9]pub*.tmp\", \"*.temp\", \"tmpfile?\" ] } - This removes files from \/tmp if they are one week old or older, + 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 @@ -140,15 +141,17 @@ Puppet::Type.newtype(:tidy) do 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*, and *m* can be appended to specify *bytes*, *kilobytes*, - and *megabytes*, respectively. Only the first character is - significant, so the full word can also be used." + *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 + be used." @@sizeconvertors = { :b => 0, :k => 1, :m => 2, - :g => 3 + :g => 3, + :t => 4 } def convert(unit, multi) diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index c7ac796a3..c8110bb69 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -12,7 +12,7 @@ module Puppet 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." + about them. It does not directly modify `/etc/passwd` or anything." feature :allows_duplicates, "The provider supports duplicate users with the same UID." @@ -24,9 +24,16 @@ module Puppet "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." + newproperty(:ensure, :parent => Puppet::Property::Ensure) do newvalue(:present, :event => :user_created) do provider.create @@ -157,6 +164,43 @@ module Puppet 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" + + 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" + 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" + + 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" + end + end + end newproperty(:groups, :parent => Puppet::Property::List) do desc "The groups of which the user is a member. The primary @@ -210,6 +254,17 @@ module Puppet 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." + + 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 = [] @@ -381,4 +436,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/whit.rb b/lib/puppet/type/whit.rb new file mode 100644 index 000000000..55bfcfb46 --- /dev/null +++ b/lib/puppet/type/whit.rb @@ -0,0 +1,11 @@ +Puppet::Type.newtype(:whit) do + desc "The smallest possible resource type, for when you need a resource and naught else." + + newparam :name do + desc "The name of the whit, because it must have one." + end + + def to_s + "Class[#{name}]" + end +end diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb index e0ed3ad37..160b2164d 100644 --- a/lib/puppet/type/yumrepo.rb +++ b/lib/puppet/type/yumrepo.rb @@ -52,8 +52,9 @@ module Puppet 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 reposdir in that file (see yum.conf(5) for details) + 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) Most parameters are identical to the ones documented in yum.conf(5) @@ -85,7 +86,7 @@ module Puppet clear inifile.each_section do |s| next if s.name == "main" - obj = create(:name => s.name, :audit => check) + obj = new(:name => s.name, :audit => check) current_values = obj.retrieve obj.eachproperty do |property| if current_values[property].nil? @@ -294,6 +295,12 @@ module Puppet newvalue(%r{(0|1)}) { } end + newproperty(:http_caching, :parent => Puppet::IniProperty) do + desc "Either 'packages' or 'all' or 'none'.\n#{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}" @@ -324,6 +331,12 @@ module Puppet 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}" newvalue(:absent) { self.should = :absent } diff --git a/lib/puppet/type/zfs.rb b/lib/puppet/type/zfs.rb index e1a972ddf..1757931f8 100755 --- a/lib/puppet/type/zfs.rb +++ b/lib/puppet/type/zfs.rb @@ -33,7 +33,7 @@ module Puppet end newproperty(:snapdir) do - desc "The sharenfs property." + desc "The snapdir property." end autorequire(:zpool) do @@ -48,4 +48,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/zone.rb b/lib/puppet/type/zone.rb index d523c469a..408d6f5dd 100644 --- a/lib/puppet/type/zone.rb +++ b/lib/puppet/type/zone.rb @@ -69,9 +69,9 @@ Puppet::Type.newtype(:zone) do 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 - only then can be ``running``. Note also that ``halt`` is currently + the states that `zoneadm` provides. The states are linear, + 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 = {} @@ -313,31 +313,31 @@ Puppet::Type.newtype(:zone) do # 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 - booted. The best way is to use a template:: - - # $templatedir/sysidcfg - 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", - realhostname => "fully.qualified.domain.name" - } + booted. The best way is to use a template: + + # $templatedir/sysidcfg + 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", + realhostname => "fully.qualified.domain.name" + } The sysidcfg only matters on the first booting of the zone, so Puppet only checks for it at that time.} diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb index 80e635504..49cce552a 100755 --- a/lib/puppet/type/zpool.rb +++ b/lib/puppet/type/zpool.rb @@ -44,8 +44,11 @@ module Puppet 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\"]" + 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?(",") @@ -53,8 +56,11 @@ module Puppet 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\"]" + 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?(",") @@ -84,4 +90,3 @@ module Puppet end end end - diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index bb4127089..850d147e2 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -3,6 +3,7 @@ require 'puppet/util/monkey_patches' require 'sync' require 'puppet/external/lock' +require 'monitor' module Puppet # A command failed to execute. @@ -17,13 +18,29 @@ module Util require 'puppet/util/posix' extend Puppet::Util::POSIX - # Create a hash to store the different sync objects. - @@syncresources = {} + @@sync_objects = {}.extend MonitorMixin - # Return the sync object associated with a given resource. - def self.sync(resource) - @@syncresources[resource] ||= Sync.new - @@syncresources[resource] + 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 @@ -181,7 +198,7 @@ module Util end end - def binary(bin) + def which(bin) if bin =~ /^\// return bin if FileTest.file? bin and FileTest.executable? bin else @@ -192,7 +209,7 @@ module Util end nil end - module_function :binary + module_function :which # Execute the provided command in a pipe, yielding the pipe object. def execpipe(command, failonfail = true) @@ -351,9 +368,7 @@ module Util # Create an exclusive lock. def threadlock(resource, type = Sync::EX) - Puppet::Util.sync(resource).synchronize(type) do - yield - end + Puppet::Util.synchronize_on(resource,type) { yield } end # Because some modules provide their own version of this method. @@ -363,15 +378,10 @@ module Util def memory unless defined?(@pmap) - pmap = %x{which pmap 2>/dev/null}.chomp - if $CHILD_STATUS != 0 or pmap =~ /^no/ - @pmap = nil - else - @pmap = pmap - end + @pmap = which('pmap') end if @pmap - return %x{pmap #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i + %x{#{@pmap} #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i else 0 end diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index c293ac14a..f0dd0a5c5 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -131,11 +131,23 @@ class Puppet::Util::Autoload # We have to require this late in the process because otherwise we might have # load order issues. require 'puppet/node/environment' - Puppet::Node::Environment.new(env).modulepath.collect do |dir| - Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f) } - end.flatten.collect { |d| [File.join(d, "plugins"), File.join(d, "lib")] }.flatten.find_all do |d| - FileTest.directory?(d) - end + + real_env = Puppet::Node::Environment.new(env) + + # We're using a per-thread cache of said module directories, so that + # we don't scan the filesystem each time we try to load something with + # this autoload instance. But since we don't want to cache for the eternity + # this env_module_directories gets reset after the compilation on the master. + # This is also reset after an agent ran. + # One of the side effect of this change is that this module directories list will be + # shared among all autoload that we have running at a time. But that won't be an issue + # as by definition those directories are shared by all autoload. + Thread.current[:env_module_directories] ||= {} + Thread.current[:env_module_directories][real_env] ||= real_env.modulepath.collect do |dir| + Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f) } + end.flatten.collect { |d| [File.join(d, "plugins"), File.join(d, "lib")] }.flatten.find_all do |d| + FileTest.directory?(d) + end end def search_directories(env=nil) diff --git a/lib/puppet/util/cacher.rb b/lib/puppet/util/cacher.rb index 8785c694f..3dddec0d4 100644 --- a/lib/puppet/util/cacher.rb +++ b/lib/puppet/util/cacher.rb @@ -1,3 +1,5 @@ +require 'monitor' + module Puppet::Util::Cacher module Expirer attr_reader :timestamp @@ -49,7 +51,7 @@ module Puppet::Util::Cacher define_method(name.to_s + "=") do |value| # Make sure the cache timestamp is set cache_timestamp - value_cache[name] = value + value_cache.synchronize { value_cache[name] = value } end if ttl = options[:ttl] @@ -70,6 +72,7 @@ module Puppet::Util::Cacher # Methods that get added to instances. module InstanceMethods + def expire # Only expire if we have an expirer. This is # mostly so that we can comfortably handle cases @@ -92,15 +95,17 @@ module Puppet::Util::Cacher end def cached_value(name) - # Allow a nil expirer, in which case we regenerate the value every time. - if expired_by_expirer?(name) - value_cache.clear - @cache_timestamp = Time.now - elsif expired_by_ttl?(name) - value_cache.delete(name) + value_cache.synchronize do + # Allow a nil expirer, in which case we regenerate the value every time. + if expired_by_expirer?(name) + value_cache.clear + @cache_timestamp = Time.now + elsif expired_by_ttl?(name) + value_cache.delete(name) + end + value_cache[name] = send("init_#{name}") unless value_cache.include?(name) + value_cache[name] end - value_cache[name] = send("init_#{name}") unless value_cache.include?(name) - value_cache[name] end def expired_by_expirer?(name) @@ -121,7 +126,7 @@ module Puppet::Util::Cacher end def value_cache - @value_cache ||= {} + @value_cache ||= {}.extend(MonitorMixin) end end end diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb index 2a97ee069..3562a3dc0 100644 --- a/lib/puppet/util/command_line.rb +++ b/lib/puppet/util/command_line.rb @@ -62,7 +62,7 @@ module Puppet external_command = "puppet-#{subcommand_name}" require 'puppet/util' - path_to_subcommand = Puppet::Util.binary( external_command ) + path_to_subcommand = Puppet::Util.which( external_command ) return false unless path_to_subcommand system( path_to_subcommand, *args ) diff --git a/lib/puppet/util/command_line/puppetdoc b/lib/puppet/util/command_line/puppetdoc index d9bbbec33..0fa1830d6 100755 --- a/lib/puppet/util/command_line/puppetdoc +++ b/lib/puppet/util/command_line/puppetdoc @@ -8,15 +8,15 @@ # # = Usage # -# puppet doc [-a|--all] [-h|--help] [-o|--outputdir <rdoc outputdir>] [-m|--mode <text|pdf|markdown|trac|rdoc>] +# puppet doc [-a|--all] [-h|--help] [-o|--outputdir <rdoc outputdir>] [-m|--mode <text|pdf|rdoc>] # [-r|--reference <[type]|configuration|..>] [--charset CHARSET] [manifest-file] # # = Description # -# If mode is not 'rdoc', then this command generates a restructured-text document describing all installed +# If mode is not 'rdoc', then this command generates a Markdown document describing all installed # Puppet types or all allowable arguments to puppet executables. It is largely # meant for internal use and is used to generate the reference document -# available on the Reductive Labs web site. +# available on the Puppet Labs web site. # # In 'rdoc' mode, this command generates an html RDoc hierarchy describing the manifests that # are in 'manifestdir' and 'modulepath' configuration directives. @@ -37,7 +37,7 @@ # Specifies the directory where to output the rdoc documentation in 'rdoc' mode. # # mode:: -# Determine the output mode. Valid modes are 'text', 'trac', 'pdf', 'markdown' and 'rdoc'. The 'pdf' and 'markdown' modes create PDF or Markdown formatted files in the /tmp directory. Note that 'trac' mode only works on Reductive Labs servers. The default mode is 'text'. In 'rdoc' mode you must provide 'manifests-path' +# Determine the output mode. Valid modes are 'text', 'trac', 'pdf' and 'rdoc'. The 'pdf' mode creates PDF formatted files in the /tmp directory. The default mode is 'text'. In 'rdoc' mode you must provide 'manifests-path' # # reference:: # Build a particular reference. Get a list of references by running +puppet doc --list+. @@ -53,7 +53,7 @@ # or # $ puppet doc /etc/puppet/manifests/site.pp # or -# $ puppet doc -m markdown -r configuration +# $ puppet doc -m pdf -r configuration # # = Author # diff --git a/lib/puppet/util/command_line/puppetrun b/lib/puppet/util/command_line/puppetrun index ee95c47eb..27cd775b9 100755 --- a/lib/puppet/util/command_line/puppetrun +++ b/lib/puppet/util/command_line/puppetrun @@ -54,8 +54,6 @@ # This is what you would install on your Puppet master; non-master hosts could # leave off the 'fileserver' and 'puppetmaster' namespaces. # -# Expect more documentation on this eventually. -# # = Options # # Note that any configuration parameter that's valid in the configuration file diff --git a/lib/puppet/util/command_line/ralsh b/lib/puppet/util/command_line/ralsh index 68ad92d84..83338fcbc 100755 --- a/lib/puppet/util/command_line/ralsh +++ b/lib/puppet/util/command_line/ralsh @@ -59,23 +59,23 @@ # types: # List all available types. # -# verbose:: +# verbose: # Print extra information. # # = Example # -# This example uses ``puppet resource`` to return Puppet configuration for the user ``luke``:: -# -# $ puppet resource user luke -# user { 'luke': -# home => '/home/luke', -# uid => '100', -# ensure => 'present', -# comment => 'Luke Kanies,,,', -# gid => '1000', -# shell => '/bin/bash', -# groups => ['sysadmin','audio','video','puppet'] -# } +# This example uses `puppet resource` to return Puppet configuration for the user `luke`: +# +# $ puppet resource user luke +# user { 'luke': +# home => '/home/luke', +# uid => '100', +# ensure => 'present', +# comment => 'Luke Kanies,,,', +# gid => '1000', +# shell => '/bin/bash', +# groups => ['sysadmin','audio','video','puppet'] +# } # # = Author # diff --git a/lib/puppet/util/docs.rb b/lib/puppet/util/docs.rb index efd054d85..4344d67ab 100644 --- a/lib/puppet/util/docs.rb +++ b/lib/puppet/util/docs.rb @@ -47,25 +47,19 @@ module Puppet::Util::Docs lengths[i] = value.to_s.length if value.to_s.length > lengths[i] end - # Add the top header row - str += lengths.collect { |num| "=" * num }.join(" ") + "\n" + # Add the header names + str += headers.zip(lengths).collect { |value, num| pad(value, num) }.join(" | ") + " |" + "\n" - # And the header names - str += headers.zip(lengths).collect { |value, num| pad(value, num) }.join(" ") + "\n" - - # And the second header row - str += lengths.collect { |num| "=" * num }.join(" ") + "\n" + # And the header row + str += lengths.collect { |num| "-" * num }.join(" | ") + " |" + "\n" # Now each data row data.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |name, rows| str += [name, rows].flatten.zip(lengths).collect do |value, length| pad(value, length) - end.join(" ") + "\n" + end.join(" | ") + " |" + "\n" end - # And the bottom line row - str += lengths.collect { |num| "=" * num }.join(" ") + "\n" - str + "\n" end @@ -111,4 +105,3 @@ module Puppet::Util::Docs module_function :scrub end - diff --git a/lib/puppet/util/file_locking.rb b/lib/puppet/util/file_locking.rb index 8b194ed83..18744cab7 100644 --- a/lib/puppet/util/file_locking.rb +++ b/lib/puppet/util/file_locking.rb @@ -6,7 +6,7 @@ module Puppet::Util::FileLocking # Create a shared lock for reading def readlock(file) raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file) - Puppet::Util.sync(file).synchronize(Sync::SH) do + Puppet::Util.synchronize_on(file,Sync::SH) do File.open(file) { |f| f.lock_shared { |lf| yield lf } } @@ -33,9 +33,12 @@ module Puppet::Util::FileLocking end end - Puppet::Util.sync(file).synchronize(Sync::EX) do - File.open(file, "w", mode) do |rf| + Puppet::Util.synchronize_on(file,Sync::EX) do + File.open(file, File::Constants::CREAT | File::Constants::WRONLY, mode) do |rf| rf.lock_exclusive do |lrf| + # poor's man open(2) O_EXLOCK|O_TRUNC + lrf.seek(0, IO::SEEK_SET) + lrf.truncate(0) yield lrf end end diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb index 36a765c61..a5aacc265 100644 --- a/lib/puppet/util/log.rb +++ b/lib/puppet/util/log.rb @@ -57,6 +57,7 @@ class Puppet::Util::Log destinations.keys.each { |dest| close(dest) } + raise Puppet::DevError.new("Log.close_all failed to close #{@destinations.keys.inspect}") if !@destinations.empty? end # Flush any log destinations that support such operations. diff --git a/lib/puppet/util/log/destinations.rb b/lib/puppet/util/log/destinations.rb index 22b3dedb2..2e2f9a5b7 100644 --- a/lib/puppet/util/log/destinations.rb +++ b/lib/puppet/util/log/destinations.rb @@ -203,8 +203,20 @@ Puppet::Util::Log.newdesttype :report do end # Log to an array, just for testing. +module Puppet::Test + class LogCollector + def initialize(logs) + @logs = logs + end + + def <<(value) + @logs << value + end + end +end + Puppet::Util::Log.newdesttype :array do - match "Array" + match "Puppet::Test::LogCollector" def initialize(messages) @messages = messages diff --git a/lib/puppet/util/metric.rb b/lib/puppet/util/metric.rb index 7e14a5fec..7fdc6951f 100644 --- a/lib/puppet/util/metric.rb +++ b/lib/puppet/util/metric.rb @@ -31,9 +31,12 @@ class Puppet::Util::Metric start ||= Time.now.to_i - 5 - @rrd = RRDtool.new(self.path) args = [] + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd = RRDtool.new(self.path) + end + values.each { |value| # the 7200 is the heartbeat -- this means that any data that isn't # more frequently than every two hours gets thrown away @@ -42,18 +45,26 @@ class Puppet::Util::Metric args.push "RRA:AVERAGE:0.5:1:300" begin - @rrd.create( Puppet[:rrdinterval].to_i, start, args) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd.create( Puppet[:rrdinterval].to_i, start, args) + else + RRD.create( self.path, '-s', Puppet[:rrdinterval].to_i.to_s, '-b', start.to_i.to_s, *args) + end rescue => detail raise "Could not create RRD file #{path}: #{detail}" end end def dump - puts @rrd.info + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + puts @rrd.info + else + puts RRD.info(self.path) + end end def graph(range = nil) - unless Puppet.features.rrd? + unless Puppet.features.rrd? || Puppet.features.rrd_legacy? Puppet.warning "RRD library is missing; cannot graph metrics" return end @@ -82,14 +93,26 @@ class Puppet::Util::Metric args << lines args.flatten! if range - args.push("--start",range[0],"--end",range[1]) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + args.push("--start",range[0],"--end",range[1]) + else + args.push("--start",range[0].to_i.to_s,"--end",range[1].to_i.to_s) + end else - args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i) + else + args.push("--start", (Time.now.to_i - time).to_s, "--end", Time.now.to_i.to_s) + end end begin #Puppet.warning "args = #{args}" - RRDtool.graph( args ) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + RRDtool.graph( args ) + else + RRD.graph( *args ) + end rescue => detail Puppet.err "Failed to graph #{self.name}: #{detail}" end @@ -99,7 +122,7 @@ class Puppet::Util::Metric def initialize(name,label = nil) @name = name.to_s - @label = label || labelize(name) + @label = label || self.class.labelize(name) @values = [] end @@ -109,18 +132,20 @@ class Puppet::Util::Metric end def newvalue(name,value,label = nil) - label ||= labelize(name) + label ||= self.class.labelize(name) @values.push [name,label,value] end def store(time) - unless Puppet.features.rrd? + unless Puppet.features.rrd? || Puppet.features.rrd_legacy? Puppet.warning "RRD library is missing; cannot store metrics" return end self.create(time - 5) unless FileTest.exists?(self.path) - @rrd ||= RRDtool.new(self.path) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd ||= RRDtool.new(self.path) + end # XXX this is not terribly error-resistant args = [time] @@ -133,7 +158,11 @@ class Puppet::Util::Metric arg = args.join(":") template = temps.join(":") begin - @rrd.update( template, [ arg ] ) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd.update( template, [ arg ] ) + else + RRD.update( self.path, '-t', template, arg ) + end #system("rrdtool updatev #{self.path} '#{arg}'") rescue => detail raise Puppet::Error, "Failed to update #{self.name}: #{detail}" @@ -144,10 +173,8 @@ class Puppet::Util::Metric @values.sort { |a, b| a[1] <=> b[1] } end - private - # Convert a name into a label. - def labelize(name) + def self.labelize(name) name.to_s.capitalize.gsub("_", " ") end end diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb index e035afd9f..1c35ae523 100644 --- a/lib/puppet/util/monkey_patches.rb +++ b/lib/puppet/util/monkey_patches.rb @@ -1,4 +1,7 @@ -Process.maxgroups = 1024 + +unless defined? JRUBY_VERSION + Process.maxgroups = 1024 +end module RDoc def self.caller(skip=nil) @@ -22,7 +25,7 @@ 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 + def to_yaml(ignored=nil) ZAML.dump(self) end end @@ -45,3 +48,26 @@ if RUBY_VERSION == '1.8.7' 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 +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 diff --git a/lib/puppet/util/nagios_maker.rb b/lib/puppet/util/nagios_maker.rb index 59ed820f9..863fe24fa 100644 --- a/lib/puppet/util/nagios_maker.rb +++ b/lib/puppet/util/nagios_maker.rb @@ -45,17 +45,16 @@ module Puppet::Util::NagiosMaker 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 + 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. + 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* + You can purge Nagios resources using the `resources` type, but *only* in the default file locations. This is an architectural limitation. - .. _naginator: http://projects.reductivelabs.com/projects/naginator " end end diff --git a/lib/puppet/util/provider_features.rb b/lib/puppet/util/provider_features.rb index ac294d20d..30e8dcb39 100644 --- a/lib/puppet/util/provider_features.rb +++ b/lib/puppet/util/provider_features.rb @@ -72,7 +72,7 @@ module Puppet::Util::ProviderFeatures names = @features.keys.sort { |a,b| a.to_s <=> b.to_s } names.each do |name| doc = @features[name].docs.gsub(/\n\s+/, " ") - str += "- **#{name}**: #{doc}\n" + str += "- *#{name}*: #{doc}\n" end if providers.length > 0 @@ -83,7 +83,7 @@ module Puppet::Util::ProviderFeatures prov = provider(provname) names.each do |name| if prov.feature?(name) - data[provname] << "**X**" + data[provname] << "*X*" else data[provname] << "" end diff --git a/lib/puppet/util/rdoc.rb b/lib/puppet/util/rdoc.rb index 4a80b069b..bdac579d6 100644 --- a/lib/puppet/util/rdoc.rb +++ b/lib/puppet/util/rdoc.rb @@ -10,24 +10,25 @@ module Puppet::Util::RDoc # then rdoc require 'rdoc/rdoc' + require 'rdoc/options' # load our parser require 'puppet/util/rdoc/parser' r = RDoc::RDoc.new - RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new( + RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new( "puppet/util/rdoc/generators/puppet_generator.rb", - "PuppetGenerator".intern, + "PuppetGenerator".intern, + "puppet") - "puppet") # specify our own format & where to output options = [ "--fmt", "puppet", "--quiet", - "--force-update", "--exclude", "/modules/[^/]*/files/.*\.pp$", "--op", outputdir ] + options << "--force-update" if Options::OptionList.options.any? { |o| o[0] == "--force-update" } options += [ "--charset", charset] if charset options += files @@ -41,7 +42,7 @@ module Puppet::Util::RDoc def manifestdoc(files) Puppet[:ignoreimport] = true files.select { |f| FileTest.file?(f) }.each do |f| - parser = Puppet::Parser::Parser.new(:environment => Puppet[:environment]) + parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new(Puppet[:environment])) parser.file = f ast = parser.parse output(f, ast) diff --git a/lib/puppet/util/rdoc/generators/puppet_generator.rb b/lib/puppet/util/rdoc/generators/puppet_generator.rb index 9caeacd5e..e6bbb2e1e 100644 --- a/lib/puppet/util/rdoc/generators/puppet_generator.rb +++ b/lib/puppet/util/rdoc/generators/puppet_generator.rb @@ -88,6 +88,12 @@ module Generators @modules = {} @allclasses = {} + # remove unknown toplevels + # it can happen that RDoc triggers a different parser for some files (ie .c, .cc or .h) + # in this case RDoc generates a RDoc::TopLevel which we do not support in this generator + # So let's make sure we don't generate html for those. + @toplevels = @toplevels.select { |tl| tl.is_a? RDoc::PuppetTopLevel } + # build the modules, classes and per modules classes and define list @toplevels.each do |toplevel| next unless toplevel.document_self diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb index 573d1766f..ce34442ab 100644 --- a/lib/puppet/util/rdoc/parser.rb +++ b/lib/puppet/util/rdoc/parser.rb @@ -15,7 +15,9 @@ module RDoc class Parser extend ParserFactory - attr_accessor :ast, :input_file_name, :top_level + SITE = "__site__" + + attr_accessor :input_file_name, :top_level # parser registration into RDoc parse_files_matching(/\.(rb|pp)$/) @@ -31,13 +33,19 @@ class Parser # main entry point def scan - Puppet.info "rdoc: scanning #{@input_file_name}" - if @input_file_name =~ /\.pp$/ - @parser = Puppet::Parser::Parser.new(Puppet[:environment]) - @parser.file = @input_file_name - @ast = @parser.parse + environment = Puppet::Node::Environment.new + unless environment.known_resource_types.watching_file?(@input_file_name) + Puppet.info "rdoc: scanning #{@input_file_name}" + if @input_file_name =~ /\.pp$/ + @parser = Puppet::Parser::Parser.new(environment) + @parser.file = @input_file_name + @known_resource_types = environment.known_resource_types + @parser.parse.instantiate('').each do |type| + @known_resource_types.add type + end + scan_top_level(@top_level) + end end - scan_top_level(@top_level) @top_level end @@ -74,7 +82,7 @@ class Parser # split_module tries to find if +path+ belongs to the module path # if it does, it returns the module name, otherwise if we are sure - # it is part of the global manifest path, "<site>" is returned. + # it is part of the global manifest path, "__site__" is returned. # And finally if this path couldn't be mapped anywhere, nil is returned. def split_module(path) # find a module @@ -105,7 +113,7 @@ class Parser end # we are under a global manifests Puppet.debug "rdoc: global manifests" - "<site>" + SITE end # create documentation for the top level +container+ @@ -128,7 +136,7 @@ class Parser Puppet.debug "rdoc: scanning for #{name}" container.module_name = name - container.global=true if name == "<site>" + container.global=true if name == SITE @stats.num_modules += 1 container, name = get_class_or_module(container,name) @@ -199,19 +207,21 @@ class Parser if stmt.is_a?(Puppet::Parser::AST::Resource) and !stmt.type.nil? begin type = stmt.type.split("::").collect { |s| s.capitalize }.join("::") - title = stmt.title.is_a?(Puppet::Parser::AST::ASTArray) ? stmt.title.to_s.gsub(/\[(.*)\]/,'\1') : stmt.title.to_s - Puppet.debug "rdoc: found resource: #{type}[#{title}]" + stmt.instances.each do |inst| + title = inst.title.is_a?(Puppet::Parser::AST::ASTArray) ? inst.title.to_s.gsub(/\[(.*)\]/,'\1') : inst.title.to_s + Puppet.debug "rdoc: found resource: #{type}[#{title}]" - param = [] - stmt.params.children.each do |p| - res = {} - res["name"] = p.param - res["value"] = "#{p.value.to_s}" unless p.value.nil? + param = [] + inst.parameters.children.each do |p| + res = {} + res["name"] = p.param + res["value"] = "#{p.value.to_s}" unless p.value.nil? - param << res - end + param << res + end - container.add_resource(PuppetResource.new(type, title, stmt.doc, param)) + container.add_resource(PuppetResource.new(type, title, stmt.doc, param)) + end rescue => detail raise Puppet::ParseError, "impossible to parse resource in #{stmt.file} at line #{stmt.line}: #{detail}" end @@ -332,7 +342,7 @@ class Parser # that contains the documentation def parse_elements(container) Puppet.debug "rdoc: scanning manifest" - @ast.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass| + @known_resource_types.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass| name = klass.name if klass.file == @input_file_name unless name.empty? @@ -345,13 +355,13 @@ class Parser end end - @ast.definitions.each do |name, define| + @known_resource_types.definitions.each do |name, define| if define.file == @input_file_name document_define(name,define,container) end end - @ast.nodes.each do |name, node| + @known_resource_types.nodes.each do |name, node| if node.file == @input_file_name document_node(name.to_s,node,container) end diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb index 62bab643e..95efeb1c1 100644 --- a/lib/puppet/util/reference.rb +++ b/lib/puppet/util/reference.rb @@ -15,7 +15,7 @@ class Puppet::Util::Reference end def self.modes - %w{pdf trac text markdown} + %w{pdf text} end def self.newreference(name, options = {}, &block) @@ -32,7 +32,6 @@ class Puppet::Util::Reference section = reference(name) or raise "Could not find section #{name}" depth = section.depth if section.depth < depth end - text = ".. contents:: :depth: 2\n\n" end def self.pdf(text) @@ -40,14 +39,7 @@ class Puppet::Util::Reference Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f| f.puts text end - rst2latex = %x{which rst2latex} - if $CHILD_STATUS != 0 or rst2latex =~ /no / - rst2latex = %x{which rst2latex.py} - end - if $CHILD_STATUS != 0 or rst2latex =~ /no / - raise "Could not find rst2latex" - end - rst2latex.chomp! + 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 @@ -67,38 +59,12 @@ class Puppet::Util::Reference end - def self.markdown(name, text) - puts "Creating markdown for #{name} reference." - dir = "/tmp/#{Puppet::PUPPETVERSION}" - FileUtils.mkdir(dir) unless File.directory?(dir) - Puppet::Util.secure_open(dir + "/#{name}.rst", "w") do |f| - f.puts text - end - pandoc = %x{which pandoc} - if $CHILD_STATUS != 0 or pandoc =~ /no / - pandoc = %x{which pandoc} - end - if $CHILD_STATUS != 0 or pandoc =~ /no / - raise "Could not find pandoc" - end - pandoc.chomp! - cmd = %{#{pandoc} -s -r rst -w markdown #{dir}/#{name}.rst -o #{dir}/#{name}.mdwn} - output = %x{#{cmd}} - unless $CHILD_STATUS == 0 - $stderr.puts "Pandoc failed to create #{name} reference." - $stderr.puts output - exit(1) - end - - File.unlink(dir + "/#{name}.rst") - end - def self.references instance_loader(:reference).loadall loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s } end - HEADER_LEVELS = [nil, "=", "-", "+", "'", "~"] + HEADER_LEVELS = [nil, "#", "##", "###", "####", "#####"] attr_accessor :page, :depth, :header, :title, :dynamic attr_writer :doc @@ -116,7 +82,7 @@ class Puppet::Util::Reference end def h(name, level) - "#{name}\n#{HEADER_LEVELS[level] * name.to_s.length}\n\n" + "#{HEADER_LEVELS[level]} #{name}\n\n" end def initialize(name, options = {}, &block) @@ -167,7 +133,6 @@ class Puppet::Util::Reference # 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 += ".. contents:: :depth: #{@depth}\n\n" if withcontents text += @header @@ -181,27 +146,4 @@ class Puppet::Util::Reference def to_text(withcontents = true) strip_trac(to_rest(withcontents)) end - - def to_trac(with_contents = true) - "{{{\n#!rst\n#{self.to_rest(with_contents)}\n}}}" - end - - def trac - Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f| - f.puts self.to_trac - end - - puts "Writing #{@name} reference to trac as #{@page}" - cmd = %{sudo trac-admin /opt/rl/trac/puppet wiki import %s /tmp/puppetdoc.txt} % self.page - output = %x{#{cmd}} - unless $CHILD_STATUS == 0 - $stderr.puts "trac-admin failed" - $stderr.puts output - exit(1) - end - unless output =~ /^\s+/ - $stderr.puts output - end - end end - diff --git a/lib/puppet/util/suidmanager.rb b/lib/puppet/util/suidmanager.rb index 4d2c32217..6633de002 100644 --- a/lib/puppet/util/suidmanager.rb +++ b/lib/puppet/util/suidmanager.rb @@ -88,7 +88,7 @@ module Puppet::Util::SUIDManager module_function :initgroups def run_and_capture(command, new_uid=nil, new_gid=nil) - output = Puppet::Util.execute(command, :failonfail => false, :uid => new_uid, :gid => new_gid) + 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 diff --git a/lib/puppet/util/zaml.rb b/lib/puppet/util/zaml.rb index 8ecc2c8bd..2155e989c 100644 --- a/lib/puppet/util/zaml.rb +++ b/lib/puppet/util/zaml.rb @@ -29,7 +29,8 @@ class ZAML @result = [] @indent = nil @structured_key_prefix = nil - Label.counter_reset + @previously_emitted_object = {} + @next_free_label_number = 0 emit('--- ') end def nested(tail=' ') @@ -55,31 +56,29 @@ class ZAML # which we will encounter a reference to the object as we serialize # it can be handled). # - def self.counter_reset - @@previously_emitted_object = {} - @@next_free_label_number = 0 - end + attr_accessor :this_label_number def initialize(obj,indent) @indent = indent @this_label_number = nil - @@previously_emitted_object[obj.object_id] = self end def to_s @this_label_number ? ('&id%03d%s' % [@this_label_number, @indent]) : '' end def reference - @this_label_number ||= (@@next_free_label_number += 1) @reference ||= '*id%03d' % @this_label_number end - def self.for(obj) - @@previously_emitted_object[obj.object_id] - end + end + def label_for(obj) + @previously_emitted_object[obj.object_id] end def new_label_for(obj) - Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"} " : ' ') + label = Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"} " : ' ') + @previously_emitted_object[obj.object_id] = label + label end def first_time_only(obj) - if label = Label.for(obj) + if label = label_for(obj) + label.this_label_number ||= (@next_free_label_number += 1) emit(label.reference) else if @structured_key_prefix and not obj.is_a? String @@ -120,6 +119,9 @@ class Object def to_yaml_properties instance_variables.sort # Default YAML behavior end + def yaml_property_munge(x) + x + end def zamlized_class_name(root) cls = self.class "!ruby/#{root.name.downcase}#{cls == root ? '' : ":#{cls.respond_to?(:name) ? cls.name : cls}"}" @@ -136,7 +138,7 @@ class Object z.nl v[1..-1].to_zaml(z) # Remove leading '@' z.emit(': ') - instance_variable_get(v).to_zaml(z) + yaml_property_munge(instance_variable_get(v)).to_zaml(z) } end } @@ -243,7 +245,6 @@ class String when self =~ /\n/ if self[-1..-1] == "\n" then z.emit('|+') else z.emit('|-') end z.nested { split("\n",-1).each { |line| z.nl; z.emit(line.chomp("\n")) } } - z.nl else z.emit(self) end diff --git a/man/man5/puppet.conf.5 b/man/man5/puppet.conf.5 index 1e4e70457..210f36786 100644 --- a/man/man5/puppet.conf.5 +++ b/man/man5/puppet.conf.5 @@ -1,1557 +1,2103 @@ -.TH CONFIGURATION REFERENCE "" "" "" -.SH NAME -Configuration Reference \- -.\" Man page generated from reStructeredText. -. -.sp -\fBThis page is autogenerated; any changes will get overwritten\fP \fI(last generated on Wed Jul 14 14:33:09 \-0700 2010)\fP -.SS Contents -.INDENT 0.0 -.IP \(bu 2 -. -\fI\%Specifying Configuration Parameters\fP -.IP \(bu 2 -. -\fI\%Signals\fP -.IP \(bu 2 -. -\fI\%Configuration Parameter Reference\fP -.UNINDENT -.SH SPECIFYING CONFIGURATION PARAMETERS -.SS On The Command\-Line -.sp -Every Puppet executable (with the exception of \fBpuppetdoc\fP) accepts all of -the parameters below, but not all of the arguments make sense for every executable. -.sp -I have tried to be as thorough as possible in the descriptions of the -arguments, so it should be obvious whether an argument is appropriate or not. -.sp -These parameters can be supplied to the executables either as command\-line -options or in the configuration file. For instance, the command\-line -invocation below would set the configuration directory to \fB/private/puppet\fP: -.sp +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "PUPPETCONF" "5" "August 2010" "" "" +\fBThis page is autogenerated; any changes will get overwritten\fR \fI(last generated on Sat Aug 28 14:00:20 \-0700 2010)\fR +. +.P +{:toc} +. +.SH "Specifying Configuration Parameters" +On The Command\-Line +++++++++++++++++++ Every Puppet executable (with the exception of \fBpuppetdoc\fR) accepts all of the parameters below, but not all of the arguments make sense for every executable\. +. +.P +I have tried to be as thorough as possible in the descriptions of the arguments, so it should be obvious whether an argument is appropriate or not\. +. +.P +These parameters can be supplied to the executables either as command\-line options or in the configuration file\. For instance, the command\-line invocation below would set the configuration directory to \fB/private/puppet\fR: +. +.IP "" 4 +. .nf -.ft C + $ puppet agent \-\-confdir=/private/puppet -.ft P +. .fi -.sp -Note that boolean options are turned on and off with a slightly different -syntax on the command line: -.sp +. +.IP "" 0 +. +.P +Note that boolean options are turned on and off with a slightly different syntax on the command line: +. +.IP "" 4 +. .nf -.ft C + $ puppet agent \-\-storeconfigs $ puppet agent \-\-no\-storeconfigs -.ft P +. .fi -.sp -The invocations above will enable and disable, respectively, the storage of -the client configuration. -.SS Configuration Files -.sp -As mentioned above, the configuration parameters can also be stored in a -configuration file, located in the configuration directory. As root, the -default configuration directory is \fB/etc/puppet\fP, and as a regular user, the -default configuration directory is \fB~user/.puppet\fP. As of 0.23.0, all -executables look for \fBpuppet.conf\fP in their configuration directory -(although they previously looked for separate files). For example, -\fBpuppet.conf\fP is located at \fB/etc/puppet/puppet.conf\fP as root and -\fB~user/.puppet/puppet.conf\fP as a regular user by default. -.sp -All executables will set any parameters set within the \fBmain\fP section, -and each executable will also use one of the \fBmaster\fP, \fBagent\fP, or -\fBuser\fP sections. -.SS File Format -.sp -The file follows INI\-style formatting. Here is an example of a very simple -\fBpuppet.conf\fP file: -.sp +. +.IP "" 0 +. +.P +The invocations above will enable and disable, respectively, the storage of the client configuration\. +. +.P +Configuration Files +++++++++++++++++++ +. +.P +As mentioned above, the configuration parameters can also be stored in a configuration file, located in the configuration directory\. As root, the default configuration directory is \fB/etc/puppet\fR, and as a regular user, the default configuration directory is \fB~user/\.puppet\fR\. As of 0\.23\.0, all executables look for \fBpuppet\.conf\fR in their configuration directory (although they previously looked for separate files)\. For example, \fBpuppet\.conf\fR is located at \fB/etc/puppet/puppet\.conf\fR as \fBroot\fR and \fB~user/\.puppet/puppet\.conf\fR as a regular user by default\. +. +.P +All executables will set any parameters set within the \fB[main]\fR section, and each executable will also use one of the \fB[master]\fR, \fB[agent]\fR\. +. +.P +File Format \'\'\'\'\'\'\'\'\'\'\' +. +.P +The file follows INI\-style formatting\. Here is an example of a very simple \fBpuppet\.conf\fR file: +. +.IP "" 4 +. .nf -.ft C + [main] confdir = /private/puppet storeconfigs = true -.ft P +. .fi -.sp -Note that boolean parameters must be explicitly specified as \fItrue\fP or -\fIfalse\fP as seen above. -.sp -If you need to change file parameters (e.g., reset the mode or owner), do -so within curly braces on the same line: -.sp +. +.IP "" 0 +. +.P +Note that boolean parameters must be explicitly specified as \fBtrue\fR or \fBfalse\fR as seen above\. +. +.P +If you need to change file parameters (e\.g\., reset the mode or owner), do so within curly braces on the same line: +. +.IP "" 4 +. .nf -.ft C + [main] myfile = /tmp/whatever {owner = root, mode = 644} -.ft P +. .fi -.sp -If you\(aqre starting out with a fresh configuration, you may wish to let -the executable generate a template configuration file for you by invoking -the executable in question with the \fI\-\-genconfig\fP command. The executable -will print a template configuration to standard output, which can be -redirected to a file like so: -.sp +. +.IP "" 0 +. +.P +If you\'re starting out with a fresh configuration, you may wish to let the executable generate a template configuration file for you by invoking the executable in question with the \fB\-\-genconfig\fR command\. The executable will print a template configuration to standard output, which can be redirected to a file like so: +. +.IP "" 4 +. .nf -.ft C -$ puppet agent \-\-genconfig > /etc/puppet/puppet.conf -.ft P + +$ puppet agent \-\-genconfig > /etc/puppet/puppet\.conf +. .fi -.sp -Note that this invocation will replace the contents of any pre\-existing -\fIpuppet.conf\fP file, so make a backup of your present config if it contains -valuable information. -.sp -Like the \fI\-\-genconfig\fP argument, the executables also accept a \fI\-\-genmanifest\fP -argument, which will generate a manifest that can be used to manage all of -Puppet\(aqs directories and files and prints it to standard output. This can -likewise be redirected to a file: -.sp +. +.IP "" 0 +. +.P +Note that this invocation will replace the contents of any pre\-existing \fBpuppet\.conf\fR file, so make a backup of your present config if it contains valuable information\. +. +.P +Like the \fB\-\-genconfig\fR argument, the executables also accept a \fB\-\-genmanifest\fR argument, which will generate a manifest that can be used to manage all of Puppet\'s directories and files and prints it to standard output\. This can likewise be redirected to a file: +. +.IP "" 4 +. .nf -.ft C -$ puppet agent \-\-genmanifest > /etc/puppet/manifests/site.pp -.ft P + +$ puppet agent \-\-genmanifest > /etc/puppet/manifests/site\.pp +. .fi -.sp -Puppet can also create user and group accounts for itself (one \fIpuppet\fP group -and one \fIpuppet\fP user) if it is invoked as \fIroot\fP with the \fI\-\-mkusers\fP argument: -.sp +. +.IP "" 0 +. +.P +Puppet can also create user and group accounts for itself (one \fBpuppet\fR group and one \fBpuppet\fR user) if it is invoked as \fBroot\fR with the \fB\-\-mkusers\fR argument: +. +.IP "" 4 +. .nf -.ft C + $ puppet agent \-\-mkusers -.ft P +. .fi -.SH SIGNALS -.sp -The \fBpuppet agent\fP and \fBpuppet master\fP executables catch some signals for special -handling. Both daemons catch (\fBSIGHUP\fP), which forces the server to restart -tself. Predictably, interrupt and terminate (\fBSIGINT\fP and \fBSIGTERM\fP) will shut -down the server, whether it be an instance of \fBpuppet agent\fP or \fBpuppet master\fP. -.sp -Sending the \fBSIGUSR1\fP signal to an instance of \fBpuppet agent\fP will cause it to -immediately begin a new configuration transaction with the server. This -signal has no effect on \fBpuppet master\fP. -.SH CONFIGURATION PARAMETER REFERENCE -.sp -Below is a list of all documented parameters. Not all of them are valid with all -Puppet executables, but the executables will ignore any inappropriate values. -.SS async_storeconfigs -.sp -Whether to use a queueing system to provide asynchronous database integration. Requires that \fBpuppetqd\fP be running and that \(aqPSON\(aq support for ruby be installed. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS authconfig -.sp -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 \fBpuppet agent\fP and \fBpuppet master\fP. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/namespaceauth.conf -.UNINDENT -.SS autoflush -.sp -Whether log files should always flush to disk. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS autosign -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/autosign.conf -.UNINDENT -.SS bindaddress -.sp -The address a listening server should bind to. Mongrel servers default to 127.0.0.1 and WEBrick defaults to 0.0.0.0. -.SS bucketdir -.sp -Where FileBucket files are stored. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/bucket -.UNINDENT -.SS ca -.sp -Wether the master should function as a certificate authority. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: true -.UNINDENT -.SS ca_days -.sp -How long a certificate should be valid. This parameter is deprecated, use ca_ttl instead -.SS ca_md -.sp -The type of hash used in certificates. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: md5 -.UNINDENT -.SS ca_name -.sp -The name to use the Certificate Authority certificate. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $certname -.UNINDENT -.SS ca_port -.sp -The port to use for the certificate authority. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $masterport -.UNINDENT -.SS ca_server -.sp -The server to use for certificate authority requests. It\(aqs a separate server because it cannot and does not need to horizontally scale. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $server -.UNINDENT -.SS ca_ttl -.sp -The default TTL for new certificates; valid values must be an integer, optionally followed by one of the units \(aqy\(aq (years of 365 days), \(aqd\(aq (days), \(aqh\(aq (hours), or \(aqs\(aq (seconds). The unit defaults to seconds. If this parameter is set, ca_days is ignored. Examples are \(aq3600\(aq (one hour) and \(aq1825d\(aq, which is the same as \(aq5y\(aq (5 years) -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 5y -.UNINDENT -.SS cacert -.sp -The CA certificate. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/ca_crt.pem -.UNINDENT -.SS cacrl -.sp -The certificate revocation list (CRL) for the CA. Will be used if present but otherwise ignored. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/ca_crl.pem -.UNINDENT -.SS cadir -.sp -The root directory for the certificate authority. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/ca -.UNINDENT -.SS cakey -.sp -The CA private key. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/ca_key.pem -.UNINDENT -.SS capass -.sp +. +.IP "" 0 +. +.SH "Signals" +The \fBpuppet agent\fR and \fBpuppet master\fR executables catch some signals for special handling\. Both daemons catch (\fBSIGHUP\fR), which forces the server to restart tself\. Predictably, interrupt and terminate (\fBSIGINT\fR and \fBSIGTERM\fR) will shut down the server, whether it be an instance of \fBpuppet agent\fR or \fBpuppet master\fR\. +. +.P +Sending the \fBSIGUSR1\fR signal to an instance of \fBpuppet agent\fR will cause it to immediately begin a new configuration transaction with the server\. This signal has no effect on \fBpuppet master\fR\. +. +.SH "Configuration Parameter Reference" +Below is a list of all documented parameters\. Not all of them are valid with all Puppet executables, but the executables will ignore any inappropriate values\. +. +.P +async_storeconfigs ++++++++++++++++++ +. +.P +Whether to use a queueing system to provide asynchronous database integration\. Requires that \fBpuppetqd\fR be running and that \'PSON\' support for ruby be installed\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +authconfig ++++++++++ +. +.P +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 \fBpuppet agent\fR and \fBpuppet master\fR\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/namespaceauth\.conf +. +.IP "" 0 +. +.P +autoflush +++++++++ +. +.P +Whether log files should always flush to disk\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +autosign ++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/autosign\.conf +. +.IP "" 0 +. +.P +bindaddress +++++++++++ +. +.P +The address a listening server should bind to\. Mongrel servers default to 127\.0\.0\.1 and WEBrick defaults to 0\.0\.0\.0\. +. +.P +bucketdir +++++++++ +. +.P +Where FileBucket files are stored\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/bucket +. +.IP "" 0 +. +.P +ca ++ +. +.P +Wether the master should function as a certificate authority\. +. +.IP "\(bu" 4 +\fIDefault\fR: true +. +.IP "" 0 +. +.P +ca_days +++++++ +. +.P +How long a certificate should be valid\. This parameter is deprecated, use ca_ttl instead +. +.P +ca_md +++++ +. +.P +The type of hash used in certificates\. +. +.IP "\(bu" 4 +\fIDefault\fR: md5 +. +.IP "" 0 +. +.P +ca_name +++++++ +. +.P +The name to use the Certificate Authority certificate\. +. +.IP "\(bu" 4 +\fIDefault\fR: $certname +. +.IP "" 0 +. +.P +ca_port +++++++ +. +.P +The port to use for the certificate authority\. +. +.IP "\(bu" 4 +\fIDefault\fR: $masterport +. +.IP "" 0 +. +.P +ca_server +++++++++ +. +.P +The server to use for certificate authority requests\. It\'s a separate server because it cannot and does not need to horizontally scale\. +. +.IP "\(bu" 4 +\fIDefault\fR: $server +. +.IP "" 0 +. +.P +ca_ttl ++++++ +. +.P +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) +. +.IP "\(bu" 4 +\fIDefault\fR: 5y +. +.IP "" 0 +. +.P +cacert ++++++ +. +.P +The CA certificate\. +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/ca_crt\.pem +. +.IP "" 0 +. +.P +cacrl +++++ +. +.P +The certificate revocation list (CRL) for the CA\. Will be used if present but otherwise ignored\. +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/ca_crl\.pem +. +.IP "" 0 +. +.P +cadir +++++ +. +.P +The root directory for the certificate authority\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/ca +. +.IP "" 0 +. +.P +cakey +++++ +. +.P +The CA private key\. +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/ca_key\.pem +. +.IP "" 0 +. +.P +capass ++++++ +. +.P Where the CA stores the password for the private key -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $caprivatedir/ca.pass -.UNINDENT -.SS caprivatedir -.sp -Where the CA stores private certificate information. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/private -.UNINDENT -.SS capub -.sp -The CA public key. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/ca_pub.pem -.UNINDENT -.SS catalog_format -.sp -(Deprecated for \(aqpreferred_serialization_format\(aq) What format to use to dump the catalog. Only supports \(aqmarshal\(aq and \(aqyaml\(aq. Only matters on the client, since it asks the server for a specific format. -.SS catalog_terminus -.sp -Where to get node catalogs. This is useful to change if, for instance, you\(aqd like to pre\-compile catalogs and store them in memcached or some other easily\-accessed store. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: compiler -.UNINDENT -.SS cert_inventory -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: $caprivatedir/ca\.pass +. +.IP "" 0 +. +.P +caprivatedir ++++++++++++ +. +.P +Where the CA stores private certificate information\. +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/private +. +.IP "" 0 +. +.P +capub +++++ +. +.P +The CA public key\. +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/ca_pub\.pem +. +.IP "" 0 +. +.P +catalog_format ++++++++++++++ +. +.P +(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\. +. +.P +catalog_terminus ++++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: compiler +. +.IP "" 0 +. +.P +cert_inventory ++++++++++++++ +. +.P A Complete listing of all certificates -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/inventory.txt -.UNINDENT -.SS certdir -.sp -The certificate directory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/certs -.UNINDENT -.SS certdnsnames -.sp -The DNS names on the Server certificate as a colon\-separated list. If it\(aqs 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 \(aqpuppet\(aq. -.SS certificate_revocation -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: true -.UNINDENT -.SS certname -.sp -The name to use when handling certificates. Defaults to the fully qualified domain name. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: pelin.lovedthanlost.net -.UNINDENT -.SS classfile -.sp -The file in which puppet agent stores a list of the classes associated with the retrieved configuration. Can be loaded in the separate \fBpuppet\fP executable using the \fB\-\-loadclasses\fP option. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $statedir/classes.txt -.UNINDENT -.SS client_datadir -.sp -The directory in which serialized data is stored on the client. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/client_data -.UNINDENT -.SS clientbucketdir -.sp -Where FileBucket files are stored locally. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/clientbucket -.UNINDENT -.SS clientyamldir -.sp -The directory in which client\-side YAML data is stored. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/client_yaml -.UNINDENT -.SS code -.sp -Code to parse directly. This is essentially only used by \fBpuppet\fP, and should only be set if you\(aqre writing your own Puppet executable -.SS color -.sp -Whether to use colors when logging to the console. Valid values are \fBansi\fP (equivalent to \fBtrue\fP), \fBhtml\fP (mostly used during testing with TextMate), and \fBfalse\fP, which produces no color. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: ansi -.UNINDENT -.SS confdir -.sp -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 \fBpuppet master\fP is supposed to run as, it defaults to a system directory, but if it\(aqs running as any other user, it defaults to being in \fB~\fP. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: /etc/puppet -.UNINDENT -.SS config -.sp -The configuration file for doc. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/puppet.conf -.UNINDENT -.SS config_version -.sp -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. -.SS configprint -.sp -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 \(aqall\(aq. This feature is only available in Puppet versions higher than 0.18.4. -.SS configtimeout -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 120 -.UNINDENT -.SS couchdb_url -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/inventory\.txt +. +.IP "" 0 +. +.P +certdir +++++++ +. +.P +The certificate directory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/certs +. +.IP "" 0 +. +.P +certdnsnames ++++++++++++ +. +.P +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\'\. +. +.P +certificate_revocation ++++++++++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: true +. +.IP "" 0 +. +.P +certname ++++++++ +. +.P +The name to use when handling certificates\. Defaults to the fully qualified domain name\. +. +.IP "\(bu" 4 +\fIDefault\fR: pelin\.members\.linode\.com +. +.IP "" 0 +. +.P +classfile +++++++++ +. +.P +The file in which puppet agent stores a list of the classes associated with the retrieved configuration\. Can be loaded in the separate \fBpuppet\fR executable using the \fB\-\-loadclasses\fR option\. +. +.IP "\(bu" 4 +\fIDefault\fR: $statedir/classes\.txt +. +.IP "" 0 +. +.P +client_datadir ++++++++++++++ +. +.P +The directory in which serialized data is stored on the client\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/client_data +. +.IP "" 0 +. +.P +clientbucketdir +++++++++++++++ +. +.P +Where FileBucket files are stored locally\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/clientbucket +. +.IP "" 0 +. +.P +clientyamldir +++++++++++++ +. +.P +The directory in which client\-side YAML data is stored\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/client_yaml +. +.IP "" 0 +. +.P +code ++++ +. +.P +Code to parse directly\. This is essentially only used by \fBpuppet\fR, and should only be set if you\'re writing your own Puppet executable +. +.P +color +++++ +. +.P +Whether to use colors when logging to the console\. Valid values are \fBansi\fR (equivalent to \fBtrue\fR), \fBhtml\fR (mostly used during testing with TextMate), and \fBfalse\fR, which produces no color\. +. +.IP "\(bu" 4 +\fIDefault\fR: ansi +. +.IP "" 0 +. +.P +confdir +++++++ +. +.P +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 \fBpuppet master\fR 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 \fB~\fR\. +. +.IP "\(bu" 4 +\fIDefault\fR: /etc/puppet +. +.IP "" 0 +. +.P +config ++++++ +. +.P +The configuration file for doc\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/puppet\.conf +. +.IP "" 0 +. +.P +config_version ++++++++++++++ +. +.P +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\. +. +.P +configprint +++++++++++ +. +.P +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\. +. +.P +configtimeout +++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: 120 +. +.IP "" 0 +. +.P +couchdb_url +++++++++++ +. +.P The url where the puppet couchdb database will be created -.INDENT 0.0 -.IP \(bu 2 . -\fBDefault\fP: \fI\%http://127.0.0.1:5984/puppet\fP -.UNINDENT -.SS csrdir -.sp +.IP "\(bu" 4 +\fIDefault\fR: http://127\.0\.0\.1:5984/puppet +. +.IP "" 0 +. +.P +csrdir ++++++ +. +.P Where the CA stores certificate requests -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/requests -.UNINDENT -.SS daemonize -.sp -Send the process into the background. This is the default. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: true -.UNINDENT -.SS dbadapter -.sp -The type of database to use. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: sqlite3 -.UNINDENT -.SS dbconnections -.sp -The number of database connections. Only used when networked databases are used. Will be ignored if the value is an empty string or is less than 1. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 0 -.UNINDENT -.SS dblocation -.sp -The database cache for client configurations. Used for querying within the language. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $statedir/clientconfigs.sqlite3 -.UNINDENT -.SS dbmigrate -.sp -Whether to automatically migrate the database. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS dbname -.sp -The name of the database to use. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet -.UNINDENT -.SS dbpassword -.sp -The database password for caching. Only used when networked databases are used. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet -.UNINDENT -.SS dbport -.sp -The database password for caching. Only used when networked databases are used. -.SS dbserver -.sp -The database server for caching. Only used when networked databases are used. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: localhost -.UNINDENT -.SS dbsocket -.sp -The database socket location. Only used when networked databases are used. Will be ignored if the value is an empty string. -.SS dbuser -.sp -The database user for caching. Only used when networked databases are used. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet -.UNINDENT -.SS diff -.sp -Which diff command to use when printing differences between files. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: diff -.UNINDENT -.SS diff_args -.sp -Which arguments to pass to the diff command when printing differences between files. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: \-u -.UNINDENT -.SS downcasefacts -.sp -Whether facts should be made all lowercase when sent to the server. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS dynamicfacts -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: memorysize,memoryfree,swapsize,swapfree -.UNINDENT -.SS environment -.sp -The environment Puppet is running in. For clients (e.g., \fBpuppet agent\fP) this determines the environment itself, which is used to find modules and much more. For servers (i.e., \fBpuppet master\fP) this provides the default environment for nodes we know nothing about. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: production -.UNINDENT -.SS evaltrace -.sp -Whether each resource should log when it is being evaluated. This allows you to interactively see exactly what is being done. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS external_nodes -.sp -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 \fBclasses\fP and \fBparameters\fP, where \fBclasses\fP is an array and \fBparameters\fP 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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: none -.UNINDENT -.SS factdest -.sp -Where Puppet should store facts that it pulls down from the central server. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/facts/ -.UNINDENT -.SS factpath -.sp -Where Puppet should look for facts. Multiple directories should be colon\-separated, like normal PATH variables. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/lib/facter/${\fI\%File::PATH_SEPARATOR\fP}$vardir/facts -.UNINDENT -.SS facts_terminus -.sp -Where to get node facts. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: facter -.UNINDENT -.SS factsignore -.sp -What files to ignore when pulling down facts. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: .svn CVS -.UNINDENT -.SS factsource -.sp -From where to retrieve facts. The standard Puppet \fBfile\fP type is used for retrieval, so anything that is a valid file source can be used here. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet://$server/facts/ -.UNINDENT -.SS factsync -.sp -Whether facts should be synced with the central server. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS fileserverconfig -.sp -Where the fileserver configuration is stored. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/fileserver.conf -.UNINDENT -.SS filetimeout -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 15 -.UNINDENT -.SS freeze_main -.sp -Freezes the \(aqmain\(aq class, disallowing any code to be added to it. This essentially means that you can\(aqt have any code outside of a node, class, or definition other than in the site manifest. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS genconfig -.sp -Whether to just print a configuration to stdout and exit. Only makes sense when used interactively. Takes into account arguments specified on the CLI. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS genmanifest -.sp -Whether to just print a manifest to stdout and exit. Only makes sense when used interactively. Takes into account arguments specified on the CLI. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS graph -.sp -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). -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS graphdir -.sp -Where to store dot\-outputted graphs. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $statedir/graphs -.UNINDENT -.SS group -.sp -The group puppet master should run as. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet -.UNINDENT -.SS hostcert -.sp -Where individual hosts store and look for their certificates. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $certdir/$certname.pem -.UNINDENT -.SS hostcrl -.sp -Where the host\(aqs certificate revocation list can be found. This is distinct from the certificate authority\(aqs CRL. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/crl.pem -.UNINDENT -.SS hostcsr -.sp -Where individual hosts store and look for their certificate requests. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/csr_$certname.pem -.UNINDENT -.SS hostprivkey -.sp -Where individual hosts store and look for their private key. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $privatekeydir/$certname.pem -.UNINDENT -.SS hostpubkey -.sp -Where individual hosts store and look for their public key. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $publickeydir/$certname.pem -.UNINDENT -.SS http_compression -.sp -Allow http compression in REST communication with the master. This setting might improve performance for agent \-> master communications over slow WANs. Your puppetmaster needs to support compression (usually by activating some settings in a reverse\-proxy in front of the puppetmaster, which rules out webrick). It is harmless to activate this settings if your master doesn\(aqt support compression, but if it supports it, this setting might reduce performance on high\-speed LANs. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS http_proxy_host -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: none -.UNINDENT -.SS http_proxy_port -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/requests +. +.IP "" 0 +. +.P +daemonize +++++++++ +. +.P +Send the process into the background\. This is the default\. +. +.IP "\(bu" 4 +\fIDefault\fR: true +. +.IP "" 0 +. +.P +dbadapter +++++++++ +. +.P +The type of database to use\. +. +.IP "\(bu" 4 +\fIDefault\fR: sqlite3 +. +.IP "" 0 +. +.P +dbconnections +++++++++++++ +. +.P +The number of database connections\. Only used when networked databases are used\. Will be ignored if the value is an empty string or is less than 1\. +. +.IP "\(bu" 4 +\fIDefault\fR: 0 +. +.IP "" 0 +. +.P +dblocation ++++++++++ +. +.P +The database cache for client configurations\. Used for querying within the language\. +. +.IP "\(bu" 4 +\fIDefault\fR: $statedir/clientconfigs\.sqlite3 +. +.IP "" 0 +. +.P +dbmigrate +++++++++ +. +.P +Whether to automatically migrate the database\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +dbname ++++++ +. +.P +The name of the database to use\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppet +. +.IP "" 0 +. +.P +dbpassword ++++++++++ +. +.P +The database password for caching\. Only used when networked databases are used\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppet +. +.IP "" 0 +. +.P +dbport ++++++ +. +.P +The database password for caching\. Only used when networked databases are used\. +. +.P +dbserver ++++++++ +. +.P +The database server for caching\. Only used when networked databases are used\. +. +.IP "\(bu" 4 +\fIDefault\fR: localhost +. +.IP "" 0 +. +.P +dbsocket ++++++++ +. +.P +The database socket location\. Only used when networked databases are used\. Will be ignored if the value is an empty string\. +. +.P +dbuser ++++++ +. +.P +The database user for caching\. Only used when networked databases are used\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppet +. +.IP "" 0 +. +.P +diff ++++ +. +.P +Which diff command to use when printing differences between files\. +. +.IP "\(bu" 4 +\fIDefault\fR: diff +. +.IP "" 0 +. +.P +diff_args +++++++++ +. +.P +Which arguments to pass to the diff command when printing differences between files\. +. +.IP "\(bu" 4 +\fIDefault\fR: \-u +. +.IP "" 0 +. +.P +downcasefacts +++++++++++++ +. +.P +Whether facts should be made all lowercase when sent to the server\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +dynamicfacts ++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: memorysize,memoryfree,swapsize,swapfree +. +.IP "" 0 +. +.P +environment +++++++++++ +. +.P +The environment Puppet is running in\. For clients (e\.g\., \fBpuppet agent\fR) this determines the environment itself, which is used to find modules and much more\. For servers (i\.e\., \fBpuppet master\fR) this provides the default environment for nodes we know nothing about\. +. +.IP "\(bu" 4 +\fIDefault\fR: production +. +.IP "" 0 +. +.P +evaltrace +++++++++ +. +.P +Whether each resource should log when it is being evaluated\. This allows you to interactively see exactly what is being done\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +external_nodes ++++++++++++++ +. +.P +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 \fBclasses\fR and \fBparameters\fR, where \fBclasses\fR is an array and \fBparameters\fR 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\. +. +.IP "\(bu" 4 +\fIDefault\fR: none +. +.IP "" 0 +. +.P +factdest ++++++++ +. +.P +Where Puppet should store facts that it pulls down from the central server\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/facts/ +. +.IP "" 0 +. +.P +factpath ++++++++ +. +.P +Where Puppet should look for facts\. Multiple directories should be colon\-separated, like normal PATH variables\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/lib/facter:$vardir/facts +. +.IP "" 0 +. +.P +facts_terminus ++++++++++++++ +. +.P +The node facts terminus\. +. +.IP "\(bu" 4 +\fIDefault\fR: facter +. +.IP "" 0 +. +.P +factsignore +++++++++++ +. +.P +What files to ignore when pulling down facts\. +. +.IP "\(bu" 4 +\fIDefault\fR: \.svn CVS +. +.IP "" 0 +. +.P +factsource ++++++++++ +. +.P +From where to retrieve facts\. The standard Puppet \fBfile\fR type is used for retrieval, so anything that is a valid file source can be used here\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppet://$server/facts/ +. +.IP "" 0 +. +.P +factsync ++++++++ +. +.P +Whether facts should be synced with the central server\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +fileserverconfig ++++++++++++++++ +. +.P +Where the fileserver configuration is stored\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/fileserver\.conf +. +.IP "" 0 +. +.P +filetimeout +++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: 15 +. +.IP "" 0 +. +.P +freeze_main +++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +genconfig +++++++++ +. +.P +Whether to just print a configuration to stdout and exit\. Only makes sense when used interactively\. Takes into account arguments specified on the CLI\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +genmanifest +++++++++++ +. +.P +Whether to just print a manifest to stdout and exit\. Only makes sense when used interactively\. Takes into account arguments specified on the CLI\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +graph +++++ +. +.P +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)\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +graphdir ++++++++ +. +.P +Where to store dot\-outputted graphs\. +. +.IP "\(bu" 4 +\fIDefault\fR: $statedir/graphs +. +.IP "" 0 +. +.P +group +++++ +. +.P +The group puppet master should run as\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppet +. +.IP "" 0 +. +.P +hostcert ++++++++ +. +.P +Where individual hosts store and look for their certificates\. +. +.IP "\(bu" 4 +\fIDefault\fR: $certdir/$certname\.pem +. +.IP "" 0 +. +.P +hostcrl +++++++ +. +.P +Where the host\'s certificate revocation list can be found\. This is distinct from the certificate authority\'s CRL\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/crl\.pem +. +.IP "" 0 +. +.P +hostcsr +++++++ +. +.P +Where individual hosts store and look for their certificate requests\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/csr_$certname\.pem +. +.IP "" 0 +. +.P +hostprivkey +++++++++++ +. +.P +Where individual hosts store and look for their private key\. +. +.IP "\(bu" 4 +\fIDefault\fR: $privatekeydir/$certname\.pem +. +.IP "" 0 +. +.P +hostpubkey ++++++++++ +. +.P +Where individual hosts store and look for their public key\. +. +.IP "\(bu" 4 +\fIDefault\fR: $publickeydir/$certname\.pem +. +.IP "" 0 +. +.P +http_compression ++++++++++++++++ +. +.P +Allow http compression in REST communication with the master\. This setting might improve performance for agent \-> master communications over slow WANs\. Your puppetmaster needs to support compression (usually by activating some settings in a reverse\-proxy in front of the puppetmaster, 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\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +http_proxy_host +++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: none +. +.IP "" 0 +. +.P +http_proxy_port +++++++++++++++ +. +.P The HTTP proxy port to use for outgoing connections -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 3128 -.UNINDENT -.SS httplog -.sp -Where the puppet agent web server logs. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $logdir/http.log -.UNINDENT -.SS ignorecache -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS ignoreimport -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS ignoreschedules -.sp -Boolean; whether puppet agent should ignore schedules. This is useful for initial puppet agent runs. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS keylength -.sp -The bit length of keys. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 1024 -.UNINDENT -.SS ldapattrs -.sp -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 \(aqall\(aq returns all attributes. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: all -.UNINDENT -.SS ldapbase -.sp -The search base for LDAP searches. It\(aqs impossible to provide a meaningful default here, although the LDAP libraries might have one already set. Generally, it should be the \(aqou=Hosts\(aq branch under your main directory. -.SS ldapclassattrs -.sp -The LDAP attributes to use to define Puppet classes. Values should be comma\-separated. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppetclass -.UNINDENT -.SS ldapnodes -.sp -Whether to search for node configurations in LDAP. See \fI\%http://projects.puppetlabs.com/projects/puppet/wiki/LDAP_Nodes\fP for more information. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS ldapparentattr -.sp -The attribute to use to define the parent node. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: parentnode -.UNINDENT -.SS ldappassword -.sp -The password to use to connect to LDAP. -.SS ldapport -.sp -The LDAP port. Only used if \fBldapnodes\fP is enabled. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 389 -.UNINDENT -.SS ldapserver -.sp -The LDAP server. Only used if \fBldapnodes\fP is enabled. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: ldap -.UNINDENT -.SS ldapssl -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS ldapstackedattrs -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppetvar -.UNINDENT -.SS ldapstring -.sp -The search string used to find an LDAP node. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: (&(objectclass=puppetClient)(cn=%s)) -.UNINDENT -.SS ldaptls -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS ldapuser -.sp -The user to use to connect to LDAP. Must be specified as a full DN. -.SS lexical -.sp -Whether to use lexical scoping (vs. dynamic). -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS libdir -.sp -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\(aqs search path -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/lib -.UNINDENT -.SS listen -.sp -Whether puppet agent should listen for connections. If this is true, then by default only the \fBrunner\fP server is started, which allows remote authorized and authenticated nodes to connect and trigger \fBpuppet agent\fP runs. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS localcacert -.sp -Where each client stores the CA certificate. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $certdir/ca.pem -.UNINDENT -.SS localconfig -.sp -Where puppet agent caches the local configuration. An extension indicating the cache format is added automatically. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $statedir/localconfig -.UNINDENT -.SS logdir -.sp -The Puppet log directory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/log -.UNINDENT -.SS manage_internal_file_permissions -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: 3128 +. +.IP "" 0 +. +.P +httplog +++++++ +. +.P +Where the puppet agent web server logs\. +. +.IP "\(bu" 4 +\fIDefault\fR: $logdir/http\.log +. +.IP "" 0 +. +.P +ignorecache +++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +ignoreimport ++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +ignoreschedules +++++++++++++++ +. +.P +Boolean; whether puppet agent should ignore schedules\. This is useful for initial puppet agent runs\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +keylength +++++++++ +. +.P +The bit length of keys\. +. +.IP "\(bu" 4 +\fIDefault\fR: 1024 +. +.IP "" 0 +. +.P +ldapattrs +++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: all +. +.IP "" 0 +. +.P +ldapbase ++++++++ +. +.P +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\. +. +.P +ldapclassattrs ++++++++++++++ +. +.P +The LDAP attributes to use to define Puppet classes\. Values should be comma\-separated\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppetclass +. +.IP "" 0 +. +.P +ldapnodes +++++++++ +. +.P +Whether to search for node configurations in LDAP\. See http://projects\.puppetlabs\.com/projects/puppet/wiki/LDAP_Nodes for more information\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +ldapparentattr ++++++++++++++ +. +.P +The attribute to use to define the parent node\. +. +.IP "\(bu" 4 +\fIDefault\fR: parentnode +. +.IP "" 0 +. +.P +ldappassword ++++++++++++ +. +.P +The password to use to connect to LDAP\. +. +.P +ldapport ++++++++ +. +.P +The LDAP port\. Only used if \fBldapnodes\fR is enabled\. +. +.IP "\(bu" 4 +\fIDefault\fR: 389 +. +.IP "" 0 +. +.P +ldapserver ++++++++++ +. +.P +The LDAP server\. Only used if \fBldapnodes\fR is enabled\. +. +.IP "\(bu" 4 +\fIDefault\fR: ldap +. +.IP "" 0 +. +.P +ldapssl +++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +ldapstackedattrs ++++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppetvar +. +.IP "" 0 +. +.P +ldapstring ++++++++++ +. +.P +The search string used to find an LDAP node\. +. +.IP "\(bu" 4 +\fIDefault\fR: (&(objectclass=puppetClient)(cn=%s)) +. +.IP "" 0 +. +.P +ldaptls +++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +ldapuser ++++++++ +. +.P +The user to use to connect to LDAP\. Must be specified as a full DN\. +. +.P +lexical +++++++ +. +.P +Whether to use lexical scoping (vs\. dynamic)\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +libdir ++++++ +. +.P +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 +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/lib +. +.IP "" 0 +. +.P +listen ++++++ +. +.P +Whether puppet agent should listen for connections\. If this is true, then by default only the \fBrunner\fR server is started, which allows remote authorized and authenticated nodes to connect and trigger \fBpuppet agent\fR runs\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +localcacert +++++++++++ +. +.P +Where each client stores the CA certificate\. +. +.IP "\(bu" 4 +\fIDefault\fR: $certdir/ca\.pem +. +.IP "" 0 +. +.P +localconfig +++++++++++ +. +.P +Where puppet agent caches the local configuration\. An extension indicating the cache format is added automatically\. +. +.IP "\(bu" 4 +\fIDefault\fR: $statedir/localconfig +. +.IP "" 0 +. +.P +logdir ++++++ +. +.P +The Puppet log directory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/log +. +.IP "" 0 +. +.P +manage_internal_file_permissions ++++++++++++++++++++++++++++++++ +. +.P Whether Puppet should manage the owner, group, and mode of files it uses internally -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: true -.UNINDENT -.SS manifest -.sp -The entry\-point manifest for puppet master. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $manifestdir/site.pp -.UNINDENT -.SS manifestdir -.sp -Where puppet master looks for its manifests. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/manifests -.UNINDENT -.SS masterhttplog -.sp -Where the puppet master web server logs. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $logdir/masterhttp.log -.UNINDENT -.SS masterlog -.sp -Where puppet master logs. This is generally not used, since syslog is the default log destination. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $logdir/puppetmaster.log -.UNINDENT -.SS masterport -.sp -Which port puppet master listens on. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 8140 -.UNINDENT -.SS maximum_uid -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 4294967290 -.UNINDENT -.SS mkusers -.sp -Whether to create the necessary user and group that puppet agent will run as. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS mode -.sp -The effective \(aqrun mode\(aq of the application: master, agent, or user. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: master -.UNINDENT -.SS modulepath -.sp -The search path for modules as a colon\-separated list of directories. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/modules:/usr/share/puppet/modules -.UNINDENT -.SS name -.sp -The name of the application, if we are running as one. The default is essentially $0 without the path or \fB.rb\fP. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: doc -.UNINDENT -.SS node_name -.sp -How the puppetmaster determines the client\(aqs identity and sets the \(aqhostname\(aq, \(aqfqdn\(aq and \(aqdomain\(aq facts for use in the manifest, in particular for determining which \(aqnode\(aq statement applies to the client. Possible values are \(aqcert\(aq (use the subject\(aqs CN in the client\(aqs certificate) and \(aqfacter\(aq (use the hostname that the client reported in its facts) -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: cert -.UNINDENT -.SS node_terminus -.sp -Where to find information about nodes. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: plain -.UNINDENT -.SS noop -.sp -Whether puppet agent should be run in noop mode. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS onetime -.sp -Run the configuration once, rather than as a long\-running daemon. This is useful for interactively running puppetd. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS parseonly -.sp -Just check the syntax of the manifests. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS passfile -.sp -Where puppet agent stores the password for its private key. Generally unused. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $privatedir/password -.UNINDENT -.SS path -.sp -The shell search path. Defaults to whatever is inherited from the parent process. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: none -.UNINDENT -.SS pidfile -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: true +. +.IP "" 0 +. +.P +manifest ++++++++ +. +.P +The entry\-point manifest for puppet master\. +. +.IP "\(bu" 4 +\fIDefault\fR: $manifestdir/site\.pp +. +.IP "" 0 +. +.P +manifestdir +++++++++++ +. +.P +Where puppet master looks for its manifests\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/manifests +. +.IP "" 0 +. +.P +masterhttplog +++++++++++++ +. +.P +Where the puppet master web server logs\. +. +.IP "\(bu" 4 +\fIDefault\fR: $logdir/masterhttp\.log +. +.IP "" 0 +. +.P +masterlog +++++++++ +. +.P +Where puppet master logs\. This is generally not used, since syslog is the default log destination\. +. +.IP "\(bu" 4 +\fIDefault\fR: $logdir/puppetmaster\.log +. +.IP "" 0 +. +.P +masterport ++++++++++ +. +.P +Which port puppet master listens on\. +. +.IP "\(bu" 4 +\fIDefault\fR: 8140 +. +.IP "" 0 +. +.P +maximum_uid +++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: 4294967290 +. +.IP "" 0 +. +.P +mkusers +++++++ +. +.P +Whether to create the necessary user and group that puppet agent will run as\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +modulepath ++++++++++ +. +.P +The search path for modules as a colon\-separated list of directories\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/modules:/usr/share/puppet/modules +. +.IP "" 0 +. +.P +name ++++ +. +.P +The name of the application, if we are running as one\. The default is essentially $0 without the path or \fB\.rb\fR\. +. +.IP "\(bu" 4 +\fIDefault\fR: doc +. +.IP "" 0 +. +.P +node_name +++++++++ +. +.P +How the puppetmaster 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) +. +.IP "\(bu" 4 +\fIDefault\fR: cert +. +.IP "" 0 +. +.P +node_terminus +++++++++++++ +. +.P +Where to find information about nodes\. +. +.IP "\(bu" 4 +\fIDefault\fR: plain +. +.IP "" 0 +. +.P +noop ++++ +. +.P +Whether puppet agent should be run in noop mode\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +onetime +++++++ +. +.P +Run the configuration once, rather than as a long\-running daemon\. This is useful for interactively running puppetd\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +parseonly +++++++++ +. +.P +Just check the syntax of the manifests\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +passfile ++++++++ +. +.P +Where puppet agent stores the password for its private key\. Generally unused\. +. +.IP "\(bu" 4 +\fIDefault\fR: $privatedir/password +. +.IP "" 0 +. +.P +path ++++ +. +.P +The shell search path\. Defaults to whatever is inherited from the parent process\. +. +.IP "\(bu" 4 +\fIDefault\fR: none +. +.IP "" 0 +. +.P +pidfile +++++++ +. +.P The pid file -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $rundir/$name.pid -.UNINDENT -.SS plugindest -.sp -Where Puppet should store plugins that it pulls down from the central server. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $libdir -.UNINDENT -.SS pluginsignore -.sp -What files to ignore when pulling down plugins. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: .svn CVS .git -.UNINDENT -.SS pluginsource -.sp -From where to retrieve plugins. The standard Puppet \fBfile\fP type is used for retrieval, so anything that is a valid file source can be used here. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet://$server/plugins -.UNINDENT -.SS pluginsync -.sp -Whether plugins should be synced with the central server. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS postrun_command -.sp -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. -.SS preferred_serialization_format -.sp -The preferred means of serializing ruby instances for passing over the wire. This won\(aqt 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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: pson -.UNINDENT -.SS prerun_command -.sp -A command to run before every agent run. If this command returns a non\-zero return code, the entire Puppet run will fail. -.SS privatedir -.sp -Where the client stores private certificate information. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/private -.UNINDENT -.SS privatekeydir -.sp -The private key directory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/private_keys -.UNINDENT -.SS publickeydir -.sp -The public key directory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/public_keys -.UNINDENT -.SS puppetdlockfile -.sp -A lock file to temporarily stop puppet agent from doing anything. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $statedir/puppetdlock -.UNINDENT -.SS puppetdlog -.sp -The log file for puppet agent. This is generally not used. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $logdir/puppetd.log -.UNINDENT -.SS puppetport -.sp -Which port puppet agent listens on. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 8139 -.UNINDENT -.SS queue_source -.sp -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 -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: stomp://localhost:61613/ -.UNINDENT -.SS queue_type -.sp -Which type of queue to use for asynchronous processing. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: stomp -.UNINDENT -.SS rails_loglevel -.sp -The log level for Rails connections. The value must be a valid log level within Rails. Production environments normally use \fBinfo\fP and other environments normally use \fBdebug\fP. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: info -.UNINDENT -.SS railslog -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: $rundir/$name\.pid +. +.IP "" 0 +. +.P +plugindest ++++++++++ +. +.P +Where Puppet should store plugins that it pulls down from the central server\. +. +.IP "\(bu" 4 +\fIDefault\fR: $libdir +. +.IP "" 0 +. +.P +pluginsignore +++++++++++++ +. +.P +What files to ignore when pulling down plugins\. +. +.IP "\(bu" 4 +\fIDefault\fR: \.svn CVS \.git +. +.IP "" 0 +. +.P +pluginsource ++++++++++++ +. +.P +From where to retrieve plugins\. The standard Puppet \fBfile\fR type is used for retrieval, so anything that is a valid file source can be used here\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppet://$server/plugins +. +.IP "" 0 +. +.P +pluginsync ++++++++++ +. +.P +Whether plugins should be synced with the central server\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +postrun_command +++++++++++++++ +. +.P +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\. +. +.P +preferred_serialization_format ++++++++++++++++++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: pson +. +.IP "" 0 +. +.P +prerun_command ++++++++++++++ +. +.P +A command to run before every agent run\. If this command returns a non\-zero return code, the entire Puppet run will fail\. +. +.P +privatedir ++++++++++ +. +.P +Where the client stores private certificate information\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/private +. +.IP "" 0 +. +.P +privatekeydir +++++++++++++ +. +.P +The private key directory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/private_keys +. +.IP "" 0 +. +.P +publickeydir ++++++++++++ +. +.P +The public key directory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/public_keys +. +.IP "" 0 +. +.P +puppetdlockfile +++++++++++++++ +. +.P +A lock file to temporarily stop puppet agent from doing anything\. +. +.IP "\(bu" 4 +\fIDefault\fR: $statedir/puppetdlock +. +.IP "" 0 +. +.P +puppetdlog ++++++++++ +. +.P +The log file for puppet agent\. This is generally not used\. +. +.IP "\(bu" 4 +\fIDefault\fR: $logdir/puppetd\.log +. +.IP "" 0 +. +.P +puppetport ++++++++++ +. +.P +Which port puppet agent listens on\. +. +.IP "\(bu" 4 +\fIDefault\fR: 8139 +. +.IP "" 0 +. +.P +queue_source ++++++++++++ +. +.P +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 +. +.IP "\(bu" 4 +\fIDefault\fR: stomp://localhost:61613/ +. +.IP "" 0 +. +.P +queue_type ++++++++++ +. +.P +Which type of queue to use for asynchronous processing\. +. +.IP "\(bu" 4 +\fIDefault\fR: stomp +. +.IP "" 0 +. +.P +rails_loglevel ++++++++++++++ +. +.P +The log level for Rails connections\. The value must be a valid log level within Rails\. Production environments normally use \fBinfo\fR and other environments normally use \fBdebug\fR\. +. +.IP "\(bu" 4 +\fIDefault\fR: info +. +.IP "" 0 +. +.P +railslog ++++++++ +. +.P Where Rails\-specific logs are sent -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $logdir/rails.log -.UNINDENT -.SS report -.sp -Whether to send reports after every transaction. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS report_port -.sp -The port to communicate with the report_server. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $masterport -.UNINDENT -.SS report_server -.sp -The server to which to send transaction reports. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $server -.UNINDENT -.SS reportdir -.sp -The directory in which to store reports received from the client. Each client gets a separate subdirectory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/reports -.UNINDENT -.SS reportfrom -.sp -The \(aqfrom\(aq email address for the reports. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: \fI\%report@pelin.lovedthanlost.net\fP -.UNINDENT -.SS reports -.sp -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). -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: store -.UNINDENT -.SS reportserver -.sp -(Deprecated for \(aqreport_server\(aq) The server to which to send transaction reports. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $server -.UNINDENT -.SS reporturl -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: $logdir/rails\.log +. +.IP "" 0 +. +.P +report ++++++ +. +.P +Whether to send reports after every transaction\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +report_port +++++++++++ +. +.P +The port to communicate with the report_server\. +. +.IP "\(bu" 4 +\fIDefault\fR: $masterport +. +.IP "" 0 +. +.P +report_server +++++++++++++ +. +.P +The server to which to send transaction reports\. +. +.IP "\(bu" 4 +\fIDefault\fR: $server +. +.IP "" 0 +. +.P +reportdir +++++++++ +. +.P +The directory in which to store reports received from the client\. Each client gets a separate subdirectory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/reports +. +.IP "" 0 +. +.P +reportfrom ++++++++++ +. +.P +The \'from\' email address for the reports\. +. +.IP "\(bu" 4 +\fIDefault\fR: report@pelin\.members\.linode\.com +. +.IP "" 0 +. +.P +reports +++++++ +. +.P +The list of reports to generate\. All reports are looked for in \fBpuppet/reports/name\.rb\fR, and multiple report names should be comma\-separated (whitespace is okay)\. +. +.IP "\(bu" 4 +\fIDefault\fR: store +. +.IP "" 0 +. +.P +reportserver ++++++++++++ +. +.P +(Deprecated for \'report_server\') The server to which to send transaction reports\. +. +.IP "\(bu" 4 +\fIDefault\fR: $server +. +.IP "" 0 +. +.P +reporturl +++++++++ +. +.P The URL used by the http reports processor to send reports -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: \fI\%http://localhost:3000/reports\fP -.UNINDENT -.SS req_bits -.sp -The bit length of the certificates. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 2048 -.UNINDENT -.SS requestdir -.sp -Where host certificate requests are stored. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $ssldir/certificate_requests -.UNINDENT -.SS rest_authconfig -.sp -The configuration file that defines the rights to the different rest indirections. This can be used as a fine\-grained authorization system for \fBpuppet master\fP. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/auth.conf -.UNINDENT -.SS rrddir -.sp -The directory where RRD database files are stored. Directories for each reporting host will be created under this directory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/rrd -.UNINDENT -.SS rrdinterval -.sp -How often RRD should expect data. This should match how often the hosts report back to the server. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $runinterval -.UNINDENT -.SS rundir -.sp -Where Puppet PID files are kept. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/run -.UNINDENT -.SS runinterval -.sp -How often puppet agent applies the client configuration; in seconds. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: 1800 -.UNINDENT -.SS sendmail -.sp -Where to find the sendmail binary with which to send email. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: /usr/sbin/sendmail -.UNINDENT -.SS serial -.sp -Where the serial number for certificates is stored. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/serial -.UNINDENT -.SS server -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: http://localhost:3000/reports +. +.IP "" 0 +. +.P +req_bits ++++++++ +. +.P +The bit length of the certificates\. +. +.IP "\(bu" 4 +\fIDefault\fR: 2048 +. +.IP "" 0 +. +.P +requestdir ++++++++++ +. +.P +Where host certificate requests are stored\. +. +.IP "\(bu" 4 +\fIDefault\fR: $ssldir/certificate_requests +. +.IP "" 0 +. +.P +rest_authconfig +++++++++++++++ +. +.P +The configuration file that defines the rights to the different rest indirections\. This can be used as a fine\-grained authorization system for \fBpuppet master\fR\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/auth\.conf +. +.IP "" 0 +. +.P +rrddir ++++++ +. +.P +The directory where RRD database files are stored\. Directories for each reporting host will be created under this directory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/rrd +. +.IP "" 0 +. +.P +rrdinterval +++++++++++ +. +.P +How often RRD should expect data\. This should match how often the hosts report back to the server\. +. +.IP "\(bu" 4 +\fIDefault\fR: $runinterval +. +.IP "" 0 +. +.P +run_mode ++++++++ +. +.P +The effective \'run mode\' of the application: master, agent, or user\. +. +.IP "\(bu" 4 +\fIDefault\fR: master +. +.IP "" 0 +. +.P +rundir ++++++ +. +.P +Where Puppet PID files are kept\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/run +. +.IP "" 0 +. +.P +runinterval +++++++++++ +. +.P +How often puppet agent applies the client configuration; in seconds\. +. +.IP "\(bu" 4 +\fIDefault\fR: 1800 +. +.IP "" 0 +. +.P +sendmail ++++++++ +. +.P +Where to find the sendmail binary with which to send email\. +. +.IP "\(bu" 4 +\fIDefault\fR: /usr/sbin/sendmail +. +.IP "" 0 +. +.P +serial ++++++ +. +.P +Where the serial number for certificates is stored\. +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/serial +. +.IP "" 0 +. +.P +server ++++++ +. +.P The server to which server puppet agent should connect -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet -.UNINDENT -.SS server_datadir -.sp -The directory in which serialized data is stored, usually in a subdirectory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/server_data -.UNINDENT -.SS servertype -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: webrick -.UNINDENT -.SS show_diff -.sp -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 \fBdiff/lcs\fP Ruby library. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS signeddir -.sp -Where the CA stores signed certificates. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $cadir/signed -.UNINDENT -.SS smtpserver -.sp -The server through which to send email reports. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: none -.UNINDENT -.SS splay -.sp -Whether to sleep for a pseudo\-random (but consistent) amount of time before a run. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS splaylimit -.sp -The maximum time to delay before runs. Defaults to being the same as the run interval. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $runinterval -.UNINDENT -.SS ssl_client_header -.sp -The header containing an authenticated client\(aqs SSL DN. Only used with Mongrel. This header must be set by the proxy to the authenticated client\(aqs SSL DN (e.g., \fB/CN=puppet.puppetlabs.com\fP). See \fI\%http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel\fP for more information. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: HTTP_X_CLIENT_DN -.UNINDENT -.SS ssl_client_verify_header -.sp -The header containing the status message of the client verification. Only used with Mongrel. This header must be set by the proxy to \(aqSUCCESS\(aq if the client successfully authenticated, and anything else otherwise. See \fI\%http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel\fP for more information. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: HTTP_X_CLIENT_VERIFY -.UNINDENT -.SS ssldir -.sp -Where SSL certificates are kept. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/ssl -.UNINDENT -.SS statedir -.sp -The directory where Puppet state is stored. Generally, this directory can be removed without causing harm (although it might result in spurious service restarts). -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/state -.UNINDENT -.SS statefile -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $statedir/state.yaml -.UNINDENT -.SS storeconfigs -.sp -Whether to store each client\(aqs configuration. This requires ActiveRecord from Ruby on Rails. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS strict_hostname_checking -.sp -Whether to only search for the complete hostname as it is in the certificate when searching for node information in the catalogs. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS summarize -.sp -Whether to print a transaction summary. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS syslogfacility -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: daemon -.UNINDENT -.SS tagmap -.sp -The mapping between reporting tags and email addresses. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $confdir/tagmail.conf -.UNINDENT -.SS tags -.sp -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. -.SS templatedir -.sp -Where Puppet looks for template files. Can be a list of colon\-seperated directories. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/templates -.UNINDENT -.SS thin_storeconfigs -.sp -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 -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS trace -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: puppet +. +.IP "" 0 +. +.P +server_datadir ++++++++++++++ +. +.P +The directory in which serialized data is stored, usually in a subdirectory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/server_data +. +.IP "" 0 +. +.P +servertype ++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: webrick +. +.IP "" 0 +. +.P +show_diff +++++++++ +. +.P +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 \fBdiff/lcs\fR Ruby library\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +signeddir +++++++++ +. +.P +Where the CA stores signed certificates\. +. +.IP "\(bu" 4 +\fIDefault\fR: $cadir/signed +. +.IP "" 0 +. +.P +smtpserver ++++++++++ +. +.P +The server through which to send email reports\. +. +.IP "\(bu" 4 +\fIDefault\fR: none +. +.IP "" 0 +. +.P +splay +++++ +. +.P +Whether to sleep for a pseudo\-random (but consistent) amount of time before a run\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +splaylimit ++++++++++ +. +.P +The maximum time to delay before runs\. Defaults to being the same as the run interval\. +. +.IP "\(bu" 4 +\fIDefault\fR: $runinterval +. +.IP "" 0 +. +.P +ssl_client_header +++++++++++++++++ +. +.P +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\., \fB/CN=puppet\.puppetlabs\.com\fR)\. See http://projects\.puppetlabs\.com/projects/puppet/wiki/Using_Mongrel for more information\. +. +.IP "\(bu" 4 +\fIDefault\fR: HTTP_X_CLIENT_DN +. +.IP "" 0 +. +.P +ssl_client_verify_header ++++++++++++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: HTTP_X_CLIENT_VERIFY +. +.IP "" 0 +. +.P +ssldir ++++++ +. +.P +Where SSL certificates are kept\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/ssl +. +.IP "" 0 +. +.P +statedir ++++++++ +. +.P +The directory where Puppet state is stored\. Generally, this directory can be removed without causing harm (although it might result in spurious service restarts)\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/state +. +.IP "" 0 +. +.P +statefile +++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: $statedir/state\.yaml +. +.IP "" 0 +. +.P +storeconfigs ++++++++++++ +. +.P +Whether to store each client\'s configuration\. This requires ActiveRecord from Ruby on Rails\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +strict_hostname_checking ++++++++++++++++++++++++ +. +.P +Whether to only search for the complete hostname as it is in the certificate when searching for node information in the catalogs\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +summarize +++++++++ +. +.P +Whether to print a transaction summary\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +syslogfacility ++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: daemon +. +.IP "" 0 +. +.P +tagmap ++++++ +. +.P +The mapping between reporting tags and email addresses\. +. +.IP "\(bu" 4 +\fIDefault\fR: $confdir/tagmail\.conf +. +.IP "" 0 +. +.P +tags ++++ +. +.P +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\. +. +.P +templatedir +++++++++++ +. +.P +Where Puppet looks for template files\. Can be a list of colon\-seperated directories\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/templates +. +.IP "" 0 +. +.P +thin_storeconfigs +++++++++++++++++ +. +.P +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 +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +trace +++++ +. +.P Whether to print stack traces on some errors -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS use_cached_catalog -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: false -.UNINDENT -.SS usecacheonfailure -.sp -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. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: true -.UNINDENT -.SS user -.sp -The user puppet master should run as. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: puppet -.UNINDENT -.SS vardir -.sp -Where Puppet stores dynamic and growing data. The default for this parameter is calculated specially, like \fI\%confdir\fP. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: /var/lib/puppet -.UNINDENT -.SS yamldir -.sp -The directory in which YAML data is stored, usually in a subdirectory. -.INDENT 0.0 -.IP \(bu 2 -. -\fBDefault\fP: $vardir/yaml -.UNINDENT -.SS zlib -.sp +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +use_cached_catalog ++++++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: false +. +.IP "" 0 +. +.P +usecacheonfailure +++++++++++++++++ +. +.P +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\. +. +.IP "\(bu" 4 +\fIDefault\fR: true +. +.IP "" 0 +. +.P +user ++++ +. +.P +The user puppet master should run as\. +. +.IP "\(bu" 4 +\fIDefault\fR: puppet +. +.IP "" 0 +. +.P +vardir ++++++ +. +.P +Where Puppet stores dynamic and growing data\. The default for this parameter is calculated specially, like \fBconfdir\fR_\. +. +.IP "\(bu" 4 +\fIDefault\fR: /var/lib/puppet +. +.IP "" 0 +. +.P +yamldir +++++++ +. +.P +The directory in which YAML data is stored, usually in a subdirectory\. +. +.IP "\(bu" 4 +\fIDefault\fR: $vardir/yaml +. +.IP "" 0 +. +.P +zlib ++++ +. +.P Boolean; whether to use the zlib library -.INDENT 0.0 -.IP \(bu 2 . -\fBDefault\fP: true -.UNINDENT - -.sp -.ce ----- - -.ce 0 -.sp -.sp -\fIThis page autogenerated on Wed Jul 14 14:33:09 \-0700 2010\fP -.\" Generated by docutils manpage writer. -.\" +.IP "\(bu" 4 +\fIDefault\fR: true +. +.IP "" 0 . +.P +\fIThis page autogenerated on Sat Aug 28 14:00:20 \-0700 2010\fR diff --git a/man/man8/filebucket.8 b/man/man8/filebucket.8 index dc2d60e63..60a6eb28e 100644 --- a/man/man8/filebucket.8 +++ b/man/man8/filebucket.8 @@ -1,107 +1,105 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. -. -.SH SYNOPSIS -.sp -A stand\-alone Puppet filebucket client. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B puppet filebucket [\-h|\-\-help] [\-V|\-\-version] [\-d|\-\-debug] [\-v|\-\-verbose] -. -[\-l|\-\-local] [\-r|\-\-remote] -[\-s|\-\-server <server>] [\-b|\-\-bucket <directory>] <file> <file> ... -.UNINDENT -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -This is a stand\-alone filebucket client for sending files to a local or -central filebucket. -.SH USAGE -.sp -This client can operate in three modes, with only one mode per call: -.INDENT 0.0 -.TP -.B backup: Send one or more files to the specified file bucket. Each sent -. -file is printed with its resulting md5 sum. -.TP -.B get: Return the text associated with an md5 sum. The text is printed -. -to stdout, and only one file can be retrieved at a time. -.TP -.B restore: Given a file path and an md5 sum, store the content associated -. -with the sum into the specified file path. You can specify an -entirely new path to this argument; you are not restricted to -restoring the content to its original location. -.UNINDENT -.sp -Note that +filebucket+ defaults to using a network\-based filebucket -available on the server named +puppet+. To use this, you\(aqll have to be -running as a user with valid Puppet certificates. Alternatively, you can -use your local file bucket by specifying +\-\-local+. -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -$ puppet filebucket backup /etc/passwd -/etc/passwd: 429b225650b912a2ee067b0a4cf1e949 -$ puppet filebucket restore /tmp/passwd 429b225650b912a2ee067b0a4cf1e949 -$ -.UNINDENT -.UNINDENT -.SH OPTIONS -.sp -Note that any configuration parameter that\(aqs valid in the configuration -file is also a valid long argument. For example, \(aqssldir\(aq is a valid -configuration parameter, so you can specify \(aq\-\-ssldir <directory>\(aq as an -argument. -.sp -See the configuration file documentation at -\fI\%http://docs.puppetlabs.com/references/stable/configuration.html\fP for the -full list of acceptable parameters. A commented list of all -configuration options can also be generated by running puppet with -\(aq\-\-genconfig\(aq. -.sp -debug: Enable full debugging. -.sp -help: Print this help message -.INDENT 0.0 -.TP -.B local: Use the local filebucket. This will use the default -. -configuration information. -.TP -.B remote: Use a remote filebucket. This will use the default -. -configuration information. -.UNINDENT -.sp -server: The server to send the file to, instead of locally. -.sp -verbose: Print extra information. -.sp -version: Print version information. -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -puppet filebucket \-b /tmp/filebucket /my/file -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public -License -.\" Generated by docutils manpage writer. -.\" +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . +.TH "FILEBUCKET" "8" "August 2010" "" "" +A stand\-alone Puppet filebucket client\.puppet filebucket [\-h|\-\-help] [\-V|\-\-version] [\-d|\-\-debug] [\-v|\-\-verbose] +. +.IP "" 4 +. +.nf + + [\-l|\-\-local] [\-r|\-\-remote] + [\-s|\-\-server <server>] [\-b|\-\-bucket <directory>] <file> <file> \.\.\. +. +.fi +. +.IP "" 0 +This is a stand\-alone filebucket client for sending files to a local or central filebucket\.This client can operate in three modes, with only one mode per call: +. +.P +backup: Send one or more files to the specified file bucket\. Each sent +. +.IP "" 4 +. +.nf + + file is printed with its resulting md5 sum\. +. +.fi +. +.IP "" 0 +. +.P +get: Return the text associated with an md5 sum\. The text is printed +. +.IP "" 4 +. +.nf + + to stdout, and only one file can be retrieved at a time\. +. +.fi +. +.IP "" 0 +. +.P +restore: Given a file path and an md5 sum, store the content associated +. +.IP "" 4 +. +.nf + + with the sum into the specified file path\. You can specify an + entirely new path to this argument; you are not restricted to + restoring the content to its original location\. +. +.fi +. +.IP "" 0 +. +.P +Note that +filebucket+ defaults to using a network\-based filebucket available on the server named +puppet+\. To use this, you\'ll have to be running as a user with valid Puppet certificates\. Alternatively, you can use your local file bucket by specifying +\-\-local+\.$ puppet filebucket backup /etc/passwd /etc/passwd: 429b225650b912a2ee067b0a4cf1e949 $ puppet filebucket restore /tmp/passwd 429b225650b912a2ee067b0a4cf1e949 $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 \fIdirectory\fR\' as an argument\. +. +.P +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 with \'\-\-genconfig\'\. +. +.P +debug: Enable full debugging\. +. +.P +help: Print this help message +. +.P +local: Use the local filebucket\. This will use the default +. +.IP "" 4 +. +.nf + + configuration information\. +. +.fi +. +.IP "" 0 +. +.P +remote: Use a remote filebucket\. This will use the default +. +.IP "" 4 +. +.nf + + configuration information\. +. +.fi +. +.IP "" 0 +. +.P +server: The server to send the file to, instead of locally\. +. +.P +verbose: Print extra information\. +. +.P +version: Print version information\.puppet filebucket \-b /tmp/filebucket /my/fileLuke KaniesCopyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/pi.8 b/man/man8/pi.8 index 3e25485fc..e8f5ab531 100644 --- a/man/man8/pi.8 +++ b/man/man8/pi.8 @@ -1,50 +1,17 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.SH SYNOPSIS -.sp -Print help about puppet types on the console. Run with \(aq\-h\(aq to get -detailed help. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.sp -puppet describe [\-h|\-\-help] [\-s|\-\-short] [\-p|\-\-providers] [\-l|\-\-list] [\-m|\-\-meta] -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -Prints details of Puppet types, providers and metaparameters on the -console. -.SH OPTIONS -.sp -help: Print this help text -.sp +.TH "PI" "8" "August 2010" "" "" +Print help about puppet types on the console\. Run with \'\-h\' to get detailed help\.puppet describe [\-h|\-\-help] [\-s|\-\-short] [\-p|\-\-providers] [\-l|\-\-list] [\-m|\-\-meta]Prints details of Puppet types, providers and metaparameters on the console\.help: Print this help text +. +.P providers: Describe providers in detail for each type -.sp -list: List all types -.sp -meta: List all metaparameters -.sp -short: List only parameters without detail -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -puppet describe \-\-list -puppet describe file \-\-providers -puppet describe user \-s \-m -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -David Lutterkort -.SH COPYRIGHT -.sp -Copyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public -License -.\" Generated by docutils manpage writer. -.\" . +.P +list: List all types +. +.P +meta: List all metaparameters +. +.P +short: List only parameters without detailpuppet describe \-\-list puppet describe file \-\-providers puppet describe user \-s \-mDavid LutterkortCopyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/puppet.8 b/man/man8/puppet.8 index 7fa2a05c2..513d45338 100644 --- a/man/man8/puppet.8 +++ b/man/man8/puppet.8 @@ -1,11 +1,10 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.sp -Usage: puppet command <space separated arguments> -Available commands are: agent, apply, cert, describe, doc, filebucket, kick, master, pi, puppet, puppetca, puppetd, puppetdoc, puppetmasterd, puppetqd, puppetrun, queue, ralsh, resource -.\" Generated by docutils manpage writer. -.\" +.TH "PUPPET" "8" "August 2010" "" "" . +.SH "NAME" +\fBpuppet\fR +. +.P +Usage: puppet command \fIspace separated arguments\fR Available commands are: agent, apply, cert, describe, doc, filebucket, kick, master, queue, resource diff --git a/man/man8/puppetca.8 b/man/man8/puppetca.8 index ec1f5045c..17369aa20 100644 --- a/man/man8/puppetca.8 +++ b/man/man8/puppetca.8 @@ -1,130 +1,169 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. -. -.SH SYNOPSIS -.sp -Stand\-alone certificate authority. Capable of generating certificates -but mostly meant for signing certificate requests from puppet clients. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B puppet cert [\-h|\-\-help] [\-V|\-\-version] [\-d|\-\-debug] [\-v|\-\-verbose] -. -[\-g|\-\-generate] [\-l|\-\-list] [\-s|\-\-sign] [\-r|\-\-revoke] -[\-p|\-\-print] [\-c|\-\-clean] [\-\-verify] [\-\-digest DIGEST] -[\-\-fingerprint] [host] -.UNINDENT -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -Because the puppetmasterd daemon 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. -.SH OPTIONS -.sp -Note that any configuration parameter that\(aqs valid in the configuration -file is also a valid long argument. For example, \(aqssldir\(aq is a valid -configuration parameter, so you can specify \(aq\-\-ssldir <directory>\(aq as an -argument. -.sp -See the configuration file documentation at -\fI\%http://reductivelabs.com/projects/puppet/reference/configref.html\fP for -the full list of acceptable parameters. A commented list of all -configuration options can also be generated by running puppet cert with -\(aq\-\-genconfig\(aq. -.INDENT 0.0 -.TP -.B all: Operate on all items. Currently only makes sense with -. -\(aq\-\-sign\(aq, \(aq\-\-clean\(aq, or \(aq\-\-list\(aq. -.TP -.B 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. -.TP -.B clean: Remove all files related to a host from puppet cert\(aqs -. -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. The certificate of the host remains valid. If \(aq\-\-all\(aq -is specified then all host certificates, both signed and -unsigned, will be removed. -.UNINDENT -.sp -debug: Enable full debugging. -.INDENT 0.0 -.TP -.B generate: Generate a certificate for a named client. A -. -certificate/keypair will be generated for each client named -on the command line. -.UNINDENT -.sp -help: Print this help message -.INDENT 0.0 -.TP -.B list: List outstanding certificate requests. If \(aq\-\-all\(aq is -. -specified, signed certificates are also listed, prefixed by -\(aq+\(aq, and revoked or invalid certificates are prefixed by -\(aq\-\(aq (the verification outcome is printed in parenthesis). -.UNINDENT -.sp -print: Print the full\-text version of a host\(aqs certificate. -.INDENT 0.0 -.TP -.B fingerprint: Print the DIGEST (defaults to md5) fingerprint of a host\(aqs -. -certificate. -.TP -.B 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 \(aq0x\(aq, or by its -hostname. The certificate is revoked by adding it to the -Certificate Revocation List given by the \(aqcacrl\(aq config -parameter. Note that the puppetmasterd needs to be -restarted after revoking certificates. -.TP -.B sign: Sign an outstanding certificate request. Unless \(aq\-\-all\(aq is -. -specified, hosts must be listed after all flags. -.UNINDENT -.sp -verbose: Enable verbosity. -.sp -version: Print the puppet version number and exit. -.INDENT 0.0 -.TP -.B verify: Verify the named certificate against the local CA -. -certificate. -.UNINDENT -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -$ puppet cert \-l -culain.madstop.com -$ puppet cert \-s culain.madstop.com -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public -License -.\" Generated by docutils manpage writer. -.\" +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . +.TH "PUPPETCA" "8" "August 2010" "" "" +Stand\-alone certificate authority\. Capable of generating certificates but mostly meant for signing certificate requests from puppet clients\.puppet cert [\-h|\-\-help] [\-V|\-\-version] [\-d|\-\-debug] [\-v|\-\-verbose] +. +.IP "" 4 +. +.nf + + [\-g|\-\-generate] [\-l|\-\-list] [\-s|\-\-sign] [\-r|\-\-revoke] + [\-p|\-\-print] [\-c|\-\-clean] [\-\-verify] [\-\-digest DIGEST] + [\-\-fingerprint] [host] +. +.fi +. +.IP "" 0 +Because the puppetmasterd daemon 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\.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 \fIdirectory\fR\' as an argument\. +. +.P +See the configuration file documentation at http://reductivelabs\.com/projects/puppet/reference/configref\.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\'\. +. +.P +all: Operate on all items\. Currently only makes sense with +. +.IP "" 4 +. +.nf + + \'\-\-sign\', \'\-\-clean\', or \'\-\-list\'\. +. +.fi +. +.IP "" 0 +. +.P +digest: Set the digest for fingerprinting (defaults to md5)\. Valid +. +.IP "" 4 +. +.nf + + values depends on your openssl and openssl ruby extension + version, but should contain at least md5, sha1, md2, + sha256\. +. +.fi +. +.IP "" 0 +. +.P +clean: Remove all files related to a host from puppet cert\'s +. +.IP "" 4 +. +.nf + + 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\. The certificate of the host remains valid\. If \'\-\-all\' + is specified then all host certificates, both signed and + unsigned, will be removed\. +. +.fi +. +.IP "" 0 +. +.P +debug: Enable full debugging\. +. +.P +generate: Generate a certificate for a named client\. A +. +.IP "" 4 +. +.nf + + certificate/keypair will be generated for each client named + on the command line\. +. +.fi +. +.IP "" 0 +. +.P +help: Print this help message +. +.P +list: List outstanding certificate requests\. If \'\-\-all\' is +. +.IP "" 4 +. +.nf + + specified, signed certificates are also listed, prefixed by + \'+\', and revoked or invalid certificates are prefixed by + \'\-\' (the verification outcome is printed in parenthesis)\. +. +.fi +. +.IP "" 0 +. +.P +print: Print the full\-text version of a host\'s certificate\. +. +.P +fingerprint: Print the DIGEST (defaults to md5) fingerprint of a host\'s +. +.IP "" 4 +. +.nf + + certificate\. +. +.fi +. +.IP "" 0 +. +.P +revoke: Revoke the certificate of a client\. The certificate can be +. +.IP "" 4 +. +.nf + + 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\' config + parameter\. Note that the puppetmasterd needs to be + restarted after revoking certificates\. +. +.fi +. +.IP "" 0 +. +.P +sign: Sign an outstanding certificate request\. Unless \'\-\-all\' is +. +.IP "" 4 +. +.nf + + specified, hosts must be listed after all flags\. +. +.fi +. +.IP "" 0 +. +.P +verbose: Enable verbosity\. +. +.P +version: Print the puppet version number and exit\. +. +.P +verify: Verify the named certificate against the local CA +. +.IP "" 4 +. +.nf + + certificate\. +. +.fi +. +.IP "" 0 +$ puppet cert \-l culain\.madstop\.com $ puppet cert \-s culain\.madstop\.comLuke KaniesCopyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/puppetd.8 b/man/man8/puppetd.8 index 090c3342d..32aede791 100644 --- a/man/man8/puppetd.8 +++ b/man/man8/puppetd.8 @@ -1,227 +1,283 @@ -.TH SYNOPSIS "" "" "" -.SH NAME -Synopsis \- -.\" Man page generated from reStructeredText. -. -.sp -Retrieve the client configuration from the puppet master and apply it to -the local host. -.sp -Currently must be run out periodically, using cron or something similar. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B puppet agent [\-D|\-\-daemonize|\-\-no\-daemonize] [\-d|\-\-debug] -. -[\-\-detailed\-exitcodes] [\-\-disable] [\-\-enable] -[\-h|\-\-help] [\-\-fqdn <host name>] [\-l|\-\-logdest syslog|<file>|console] -[\-o|\-\-onetime] [\-\-serve <handler>] [\-t|\-\-test] [\-\-noop] -[\-\-digest <digest>] [\-\-fingerprint] [\-V|\-\-version] -[\-v|\-\-verbose] [\-w|\-\-waitforcert <seconds>] -.UNINDENT -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -This is the main puppet client. Its job is to retrieve the local -machine\(aqs configuration from a remote server and apply it. In order to -successfully communicate with the remote server, the client must have a -certificate signed by a certificate authority that the server trusts; -the recommended method for this, at the moment, is to run a certificate -authority as part of the puppet server (which is the default). The -client will connect and request a signed certificate, and will continue -connecting until it receives one. -.sp -Once the client has a signed certificate, it will retrieve its -configuration and apply it. -.SH USAGE NOTES -.sp -+puppet agent+ does its best to find a compromise between interactive -use and daemon use. Run with no arguments and no configuration, it will -go into the backgroun, attempt to get a signed certificate, and retrieve -and apply its configuration every 30 minutes. -.sp -Some flags are meant specifically for interactive use \-\- in particular, -+test+, +tags+ or +fingerprint+ are useful. +test+ enables verbose -logging, causes the daemon to stay in the foreground, exits if the -server\(aqs configuration is invalid (this happens if, for instance, you\(aqve -left a syntax error on the server), and exits after running the -configuration once (rather than hanging around as a long\-running -process). -.sp -+tags+ allows you to specify what portions of a configuration you want -to apply. Puppet elements are tagged with all of the class or definition -names that contain them, and you can use the +tags+ flag to specify one -of these names, causing only configuration elements contained within -that class or definition to be applied. This is very useful when you are -testing new configurations \-\- for instance, if you are just starting to -manage +ntpd+, you would put all of the new elements into an +ntpd+ -class, and call puppet with +\-\-tags ntpd+, which would only apply that -small portion of the configuration during your testing, rather than -applying the whole thing. -.sp -+fingerprint+ is a one\-time flag. In this mode +puppet agent+ will run -once and display on the console (and in the log) the current certificate -(or certificate request) fingerprint. Providing the +\-\-digest+ option -allows to use a different digest algorithm to generate the fingerprint. -The main use is to verify that before signing a certificate request on -the master, the certificate request the master received is the same as -the one the client sent (to prevent against man\-in\-the\-middle attacks -when signing certificates). -.SH OPTIONS -.sp -Note that any configuration parameter that\(aqs valid in the configuration -file is also a valid long argument. For example, \(aqserver\(aq is a valid -configuration parameter, so you can specify \(aq\-\-server <servername>\(aq as -an argument. -.sp -See the configuration file documentation at -\fI\%http://docs.puppetlabs.com/references/stable/configuration.html\fP for the -full list of acceptable parameters. A commented list of all -configuration options can also be generated by running puppet agent with -\(aq\-\-genconfig\(aq. -.INDENT 0.0 -.TP -.B daemonize: Send the process into the background. This is the -. -default. -.UNINDENT -.sp -no\-daemonize: Do not send the process into the background. -.sp -debug: Enable full debugging. -.INDENT 0.0 -.TP -.B digest: Change the certificate fingerprinting digest -. -algorithm. The default is MD5. Valid values depends -on the version of OpenSSL installed, but should -always at least contain MD5, MD2, SHA1 and SHA256. -.TP -.B detailed\-exitcodes: Provide transaction information via exit codes. If -. -this is enabled, an exit code of \(aq2\(aq means there -were changes, and an exit code of \(aq4\(aq means that -there were failures during the transaction. This -option only makes sense in conjunction with -\-\-onetime. -.TP -.B disable: Disable working on the local system. This puts a -. -lock file in place, causing +puppet agent+ not to -work on the system until the lock file is removed. -This is useful if you are testing a configuration -and do not want the central configuration to -override the local state until everything is tested -and committed. -.UNINDENT -.sp -+puppet agent+ uses the same lock file while it is running, so no more -than one +puppet agent+ process is working at a time. -.sp -+puppet agent+ exits after executing this. -.INDENT 0.0 -.TP -.B enable: Enable working on the local system. This removes any -. -lock file, causing +puppet agent+ to start managing -the local system again (although it will continue to -use its normal scheduling, so it might not start for -another half hour). -.UNINDENT -.sp -+puppet agent+ exits after executing this. -.INDENT 0.0 -.TP -.B fqdn: Set the fully\-qualified domain name of the client. -. -This is only used for certificate purposes, but can -be used to override the discovered hostname. If you -need to use this flag, it is generally an indication -of a setup problem. -.UNINDENT -.sp -help: Print this help message -.INDENT 0.0 -.TP -.B logdest: Where to send messages. Choose between syslog, the -. -console, and a log file. Defaults to sending -messages to syslog, or the console if debugging or -verbosity is enabled. -.TP -.B no\-client: Do not create a config client. This will cause the -. -daemon to run without ever checking for its -configuration automatically, and only makes sense -when used in conjunction with \-\-listen. -.TP -.B onetime: Run the configuration once. Runs a single (normally -. -daemonized) Puppet run. Useful for interactively -running puppet agent when used in conjunction with -the \-\-no\-daemonize option. -.TP -.B fingerprint: Display the current certificate or certificate -. -signing request fingerprint and then exit. Use the -+\-\-digest+ option to change the digest algorithm -used. -.TP -.B serve: Start another type of server. By default, +puppet -. -agent+ will start a service handler that allows -authenticated and authorized remote nodes to trigger -the configuration to be pulled down and applied. You -can specify any handler here that does not require -configuration, e.g., filebucket, ca, or resource. -The handlers are in +lib/puppet/network/handler+, -and the names must match exactly, both in the call -to +serve+ and in +namespaceauth.conf+. -.TP -.B test: Enable the most common options used for testing. -. -These are +onetime+, +verbose+, +ignorecache, -+no\-daemonize+, and +no\-usecacheonfailure+. -.TP -.B noop: Use +noop+ mode where the daemon runs in a no\-op or -. -dry\-run mode. This is useful for seeing what changes -Puppet will make without actually executing the -changes. -.UNINDENT -.sp -verbose: Turn on verbose reporting. -.sp -version: Print the puppet version number and exit. -.INDENT 0.0 -.TP -.B waitforcert: This option only matters for daemons that do not yet -. -have certificates and it is enabled by default, with -a value of 120 (seconds). This causes +puppet agent+ -to connect to the server every 2 minutes and ask it -to sign a certificate request. This is useful for -the initial setup of a puppet client. You can turn -off waiting for certificates by specifying a time of -0. -.UNINDENT -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -puppet agent \-\-server puppet.domain.com -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2005, 2006 Reductive Labs, LLC Licensed under the GNU -Public License -.\" Generated by docutils manpage writer. -.\" +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . +.TH "PUPPETD" "8" "August 2010" "" "" +puppet agent [\-D|\-\-daemonize|\-\-no\-daemonize] [\-d|\-\-debug] +. +.IP "" 4 +. +.nf + + [\-\-detailed\-exitcodes] [\-\-disable] [\-\-enable] + [\-h|\-\-help] [\-\-fqdn <host name>] [\-l|\-\-logdest syslog|<file>|console] + [\-o|\-\-onetime] [\-\-serve <handler>] [\-t|\-\-test] [\-\-noop] + [\-\-digest <digest>] [\-\-fingerprint] [\-V|\-\-version] + [\-v|\-\-verbose] [\-w|\-\-waitforcert <seconds>] +. +.fi +. +.IP "" 0 +This is the main puppet client\. Its job is to retrieve the local machine\'s configuration from a remote server and apply it\. In order to successfully communicate with the remote server, the client must have a certificate signed by a certificate authority that the server trusts; the recommended method for this, at the moment, is to run a certificate authority as part of the puppet server (which is the default)\. The client will connect and request a signed certificate, and will continue connecting until it receives one\. +. +.P +Once the client has a signed certificate, it will retrieve its configuration and apply it\.+puppet agent+ does its best to find a compromise between interactive use and daemon use\. Run with no arguments and no configuration, it will go into the backgroun, attempt to get a signed certificate, and retrieve and apply its configuration every 30 minutes\. +. +.P +Some flags are meant specifically for interactive use \-\- in particular, +test+, +tags+ or +fingerprint+ are useful\. +test+ enables verbose logging, causes the daemon to stay in the foreground, exits if the server\'s configuration is invalid (this happens if, for instance, you\'ve left a syntax error on the server), and exits after running the configuration once (rather than hanging around as a long\-running process)\. +. +.P ++tags+ allows you to specify what portions of a configuration you want to apply\. Puppet elements are tagged with all of the class or definition names that contain them, and you can use the +tags+ flag to specify one of these names, causing only configuration elements contained within that class or definition to be applied\. This is very useful when you are testing new configurations \-\- for instance, if you are just starting to manage +ntpd+, you would put all of the new elements into an +ntpd+ class, and call puppet with +\-\-tags ntpd+, which would only apply that small portion of the configuration during your testing, rather than applying the whole thing\. +. +.P ++fingerprint+ is a one\-time flag\. In this mode +puppet agent+ will run once and display on the console (and in the log) the current certificate (or certificate request) fingerprint\. Providing the +\-\-digest+ option allows to use a different digest algorithm to generate the fingerprint\. The main use is to verify that before signing a certificate request on the master, the certificate request the master received is the same as the one the client sent (to prevent against man\-in\-the\-middle attacks when signing certificates)\.Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument\. For example, \'server\' is a valid configuration parameter, so you can specify \'\-\-server \fIservername\fR\' as an argument\. +. +.P +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 agent with \'\-\-genconfig\'\. +. +.P +daemonize: Send the process into the background\. This is the +. +.IP "" 4 +. +.nf + + default\. +. +.fi +. +.IP "" 0 +. +.P +no\-daemonize: Do not send the process into the background\. +. +.P +debug: Enable full debugging\. +. +.P +digest: Change the certificate fingerprinting digest +. +.IP "" 4 +. +.nf + + algorithm\. The default is MD5\. Valid values depends + on the version of OpenSSL installed, but should + always at least contain MD5, MD2, SHA1 and SHA256\. +. +.fi +. +.IP "" 0 +. +.P +detailed\-exitcodes: Provide transaction information via exit codes\. If +. +.IP "" 4 +. +.nf + + this is enabled, an exit code of \'2\' means there + were changes, and an exit code of \'4\' means that + there were failures during the transaction\. This + option only makes sense in conjunction with + \-\-onetime\. +. +.fi +. +.IP "" 0 +. +.P +disable: Disable working on the local system\. This puts a +. +.IP "" 4 +. +.nf + + lock file in place, causing +puppet agent+ not to + work on the system until the lock file is removed\. + This is useful if you are testing a configuration + and do not want the central configuration to + override the local state until everything is tested + and committed\. +. +.fi +. +.IP "" 0 +. +.P ++puppet agent+ uses the same lock file while it is running, so no more than one +puppet agent+ process is working at a time\. +. +.P ++puppet agent+ exits after executing this\. +. +.P +enable: Enable working on the local system\. This removes any +. +.IP "" 4 +. +.nf + + lock file, causing +puppet agent+ to start managing + the local system again (although it will continue to + use its normal scheduling, so it might not start for + another half hour)\. +. +.fi +. +.IP "" 0 +. +.P ++puppet agent+ exits after executing this\. +. +.P +fqdn: Set the fully\-qualified domain name of the client\. +. +.IP "" 4 +. +.nf + + This is only used for certificate purposes, but can + be used to override the discovered hostname\. If you + need to use this flag, it is generally an indication + of a setup problem\. +. +.fi +. +.IP "" 0 +. +.P +help: Print this help message +. +.P +logdest: Where to send messages\. Choose between syslog, the +. +.IP "" 4 +. +.nf + + console, and a log file\. Defaults to sending + messages to syslog, or the console if debugging or + verbosity is enabled\. +. +.fi +. +.IP "" 0 +. +.P +no\-client: Do not create a config client\. This will cause the +. +.IP "" 4 +. +.nf + + daemon to run without ever checking for its + configuration automatically, and only makes sense + when used in conjunction with \-\-listen\. +. +.fi +. +.IP "" 0 +. +.P +onetime: Run the configuration once\. Runs a single (normally +. +.IP "" 4 +. +.nf + + daemonized) Puppet run\. Useful for interactively + running puppet agent when used in conjunction with + the \-\-no\-daemonize option\. +. +.fi +. +.IP "" 0 +. +.P +fingerprint: Display the current certificate or certificate +. +.IP "" 4 +. +.nf + + signing request fingerprint and then exit\. Use the + +\-\-digest+ option to change the digest algorithm + used\. +. +.fi +. +.IP "" 0 +. +.P +serve: Start another type of server\. By default, +puppet +. +.IP "" 4 +. +.nf + + agent+ will start a service handler that allows + authenticated and authorized remote nodes to trigger + the configuration to be pulled down and applied\. You + can specify any handler here that does not require + configuration, e\.g\., filebucket, ca, or resource\. + The handlers are in +lib/puppet/network/handler+, + and the names must match exactly, both in the call + to +serve+ and in +namespaceauth\.conf+\. +. +.fi +. +.IP "" 0 +. +.P +test: Enable the most common options used for testing\. +. +.IP "" 4 +. +.nf + + These are +onetime+, +verbose+, +ignorecache, + +no\-daemonize+, and +no\-usecacheonfailure+\. +. +.fi +. +.IP "" 0 +. +.P +noop: Use +noop+ mode where the daemon runs in a no\-op or +. +.IP "" 4 +. +.nf + + dry\-run mode\. This is useful for seeing what changes + Puppet will make without actually executing the + changes\. +. +.fi +. +.IP "" 0 +. +.P +verbose: Turn on verbose reporting\. +. +.P +version: Print the puppet version number and exit\. +. +.P +waitforcert: This option only matters for daemons that do not yet +. +.IP "" 4 +. +.nf + + have certificates and it is enabled by default, with + a value of 120 (seconds)\. This causes +puppet agent+ + to connect to the server every 2 minutes and ask it + to sign a certificate request\. This is useful for + the initial setup of a puppet client\. You can turn + off waiting for certificates by specifying a time of + 0\. +. +.fi +. +.IP "" 0 +puppet agent \-\-server puppet\.domain\.comLuke KaniesCopyright (c) 2005, 2006 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/puppetdoc.8 b/man/man8/puppetdoc.8 index 281b7385e..5fc01c2ba 100644 --- a/man/man8/puppetdoc.8 +++ b/man/man8/puppetdoc.8 @@ -1,108 +1,108 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. -. -.SH SYNOPSIS -.sp -Generate a reference for all Puppet types. Largely meant for internal -Reductive Labs use. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B puppet doc [\-a|\-\-all] [\-h|\-\-help] [\-o|\-\-outputdir <rdoc outputdir>] [\-m|\-\-mode <text|pdf|markdown|trac|rdoc>] -. -[\-r|\-\-reference <[type]|configuration|..>] [\-\-charset CHARSET] [manifest\-file] -.UNINDENT -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -If mode is not \(aqrdoc\(aq, then this command generates a restructured\-text -document describing all installed Puppet types or all allowable -arguments to puppet executables. It is largely meant for internal use -and is used to generate the reference document available on the -Reductive Labs web site. -.sp -In \(aqrdoc\(aq mode, this command generates an html RDoc hierarchy describing -the manifests that are in \(aqmanifestdir\(aq and \(aqmodulepath\(aq configuration -directives. The generated documentation directory is doc by default but -can be changed with the \(aqoutputdir\(aq option. -.sp -If the command is started with \(aqmanifest\-file\(aq command\-line arguments, -puppet doc generate a single manifest documentation that is output on -stdout. -.SH OPTIONS -.INDENT 0.0 -.TP -.B all: Output the docs for all of the reference types. In \(aqrdoc\(aq -. -modes, this also outputs documentation for all resources -.UNINDENT -.sp -help: Print this help message -.INDENT 0.0 -.TP -.B outputdir: Specifies the directory where to output the rdoc -. -documentation in \(aqrdoc\(aq mode. -.TP -.B mode: Determine the output mode. Valid modes are \(aqtext\(aq, \(aqtrac\(aq, -. -\(aqpdf\(aq, \(aqmarkdown\(aq and \(aqrdoc\(aq. The \(aqpdf\(aq and \(aqmarkdown\(aq modes -create PDF or Markdown formatted files in the /tmp directory. -Note that \(aqtrac\(aq mode only works on Reductive Labs servers. -The default mode is \(aqtext\(aq. In \(aqrdoc\(aq mode you must provide -\(aqmanifests\-path\(aq -.TP -.B reference: Build a particular reference. Get a list of references by -. -running +puppet doc \-\-list+. -.TP -.B charset: Used only in \(aqrdoc\(aq mode. It sets the charset used in the -. -html files produced. -.UNINDENT -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -$ puppet doc \-r type > /tmp/type_reference.rst -.UNINDENT -.UNINDENT -.sp +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "PUPPETDOC" "8" "August 2010" "" "" +Generate a reference for all Puppet types\. Largely meant for internal Reductive Labs use\.puppet doc [\-a|\-\-all] [\-h|\-\-help] [\-o|\-\-outputdir \fIrdoc outputdir\fR] [\-m|\-\-mode \fItext|pdf|rdoc\fR] +. +.IP "" 4 +. +.nf + + [\-r|\-\-reference <[type]|configuration|\.\.>] [\-\-charset CHARSET] [manifest\-file] +. +.fi +. +.IP "" 0 +If mode is not \'rdoc\', then this command generates a Markdown document describing all installed Puppet types or all allowable arguments to puppet executables\. It is largely meant for internal use and is used to generate the reference document available on the Puppet Labs web site\. +. +.P +In \'rdoc\' mode, this command generates an html RDoc hierarchy describing the manifests that are in \'manifestdir\' and \'modulepath\' configuration directives\. The generated documentation directory is doc by default but can be changed with the \'outputdir\' option\. +. +.P +If the command is started with \'manifest\-file\' command\-line arguments, puppet doc generate a single manifest documentation that is output on stdout\.all: Output the docs for all of the reference types\. In \'rdoc\' +. +.IP "" 4 +. +.nf + + modes, this also outputs documentation for all resources +. +.fi +. +.IP "" 0 +. +.P +help: Print this help message +. +.P +outputdir: Specifies the directory where to output the rdoc +. +.IP "" 4 +. +.nf + + documentation in \'rdoc\' mode\. +. +.fi +. +.IP "" 0 +. +.P +mode: Determine the output mode\. Valid modes are \'text\', \'trac\', +. +.IP "" 4 +. +.nf + + \'pdf\' and \'rdoc\'\. The \'pdf\' mode creates PDF formatted files + in the /tmp directory\. The default mode is \'text\'\. In \'rdoc\' + mode you must provide \'manifests\-path\' +. +.fi +. +.IP "" 0 +. +.P +reference: Build a particular reference\. Get a list of references by +. +.IP "" 4 +. +.nf + + running +puppet doc \-\-list+\. +. +.fi +. +.IP "" 0 +. +.P +charset: Used only in \'rdoc\' mode\. It sets the charset used in the +. +.IP "" 4 +. +.nf + + html files produced\. +. +.fi +. +.IP "" 0 +$ puppet doc \-r type > /tmp/type_reference\.rst +. +.P or -.INDENT 0.0 -.INDENT 3.5 -.sp +. +.P $ puppet doc \-\-outputdir /tmp/rdoc \-\-mode rdoc /path/to/manifests -.UNINDENT -.UNINDENT -.sp +. +.P or -.INDENT 0.0 -.INDENT 3.5 -.sp -$ puppet doc /etc/puppet/manifests/site.pp -.UNINDENT -.UNINDENT -.sp +. +.P +$ puppet doc /etc/puppet/manifests/site\.pp +. +.P or -.INDENT 0.0 -.INDENT 3.5 -.sp -$ puppet doc \-m markdown \-r configuration -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2005\-2007 Reductive Labs, LLC Licensed under the GNU -Public License -.\" Generated by docutils manpage writer. -.\" . +.P +$ puppet doc \-m pdf \-r configurationLuke KaniesCopyright (c) 2005\-2007 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/puppetmasterd.8 b/man/man8/puppetmasterd.8 index f6fb1e095..3ae567a69 100644 --- a/man/man8/puppetmasterd.8 +++ b/man/man8/puppetmasterd.8 @@ -1,72 +1,52 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. -. -.SH SYNOPSIS -.sp -The central puppet server. Functions as a certificate authority by -default. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B puppet master [\-D|\-\-daemonize|\-\-no\-daemonize] [\-d|\-\-debug] [\-h|\-\-help] -. -[\-l|\-\-logdest <file>|console|syslog] [\-v|\-\-verbose] [\-V|\-\-version] -.UNINDENT -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -This is the puppet central daemon. -.SH OPTIONS -.sp -Note that any configuration parameter that\(aqs valid in the configuration -file is also a valid long argument. For example, \(aqssldir\(aq is a valid -configuration parameter, so you can specify \(aq\-\-ssldir <directory>\(aq as an -argument. -.sp -See the configuration file documentation at -\fI\%http://docs.puppetlabs.com/references/stable/configuration.html\fP for the -full list of acceptable parameters. A commented list of all -configuration options can also be generated by running puppetmasterdd -with \(aq\-\-genconfig\(aq. -.sp -daemonize: Send the process into the background. This is the default. -.sp -no\-daemonize: Do not send the process into the background. -.sp -debug: Enable full debugging. -.sp -help: Print this help message. -.INDENT 0.0 -.TP -.B logdest: Where to send messages. Choose between syslog, the -. -console, and a log file. Defaults to sending messages to -syslog, or the console if debugging or verbosity is -enabled. -.UNINDENT -.sp -verbose: Enable verbosity. -.sp -version: Print the puppet version number and exit. -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -puppet master -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public -License -.\" Generated by docutils manpage writer. -.\" +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . +.TH "PUPPETMASTERD" "8" "August 2010" "" "" +The central puppet server\. Functions as a certificate authority by default\.puppet master [\-D|\-\-daemonize|\-\-no\-daemonize] [\-d|\-\-debug] [\-h|\-\-help] +. +.IP "" 4 +. +.nf + + [\-l|\-\-logdest <file>|console|syslog] [\-v|\-\-verbose] [\-V|\-\-version] +. +.fi +. +.IP "" 0 +This is the puppet central daemon\.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 \fIdirectory\fR\' as an argument\. +. +.P +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 puppetmasterdd with \'\-\-genconfig\'\. +. +.P +daemonize: Send the process into the background\. This is the default\. +. +.P +no\-daemonize: Do not send the process into the background\. +. +.P +debug: Enable full debugging\. +. +.P +help: Print this help message\. +. +.P +logdest: Where to send messages\. Choose between syslog, the +. +.IP "" 4 +. +.nf + + console, and a log file\. Defaults to sending messages to + syslog, or the console if debugging or verbosity is + enabled\. +. +.fi +. +.IP "" 0 +. +.P +verbose: Enable verbosity\. +. +.P +version: Print the puppet version number and exit\.puppet masterLuke KaniesCopyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/puppetqd.8 b/man/man8/puppetqd.8 index db27c664e..137a13af3 100644 --- a/man/man8/puppetqd.8 +++ b/man/man8/puppetqd.8 @@ -1,55 +1,20 @@ -.TH SYNOPSIS "" "" "" -.SH NAME -Synopsis \- -.\" Man page generated from reStructeredText. +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.sp -Retrieve serialized records from a queue and process them in order. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.sp -puppet queue [\-d|\-\-debug] [\-v|\-\-verbose] -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -This is a simple application that just processes entities in a queue as -they are recieved. -.SH OPTIONS -.sp -Note that any configuration parameter that\(aqs valid in the configuration -file is also a valid long argument. For example, \(aqserver\(aq is a valid -configuration parameter, so you can specify \(aq\-\-server <servername>\(aq as -an argument. -.sp -See the configuration file documentation at -\fI\%http://docs.puppetlabs.com/references/stable/configuration.html\fP for the -full list of acceptable parameters. A commented list of all -configuration options can also be generated by running puppetd with -\(aq\-\-genconfig\(aq. -.sp -debug: Enable full debugging. -.sp -help: Print this help message -.sp -verbose: Turn on verbose reporting. -.sp -version: Print the puppet version number and exit. -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -puppet queue -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2009 Reductive Labs, LLC Licensed under the GNU Public -License -.\" Generated by docutils manpage writer. -.\" +.TH "PUPPETQD" "8" "August 2010" "" "" +puppet queue [\-d|\-\-debug] [\-v|\-\-verbose]This is a simple application that just processes entities in a queue as they are recieved\.Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument\. For example, \'server\' is a valid configuration parameter, so you can specify \'\-\-server \fIservername\fR\' as an argument\. . +.P +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 puppetd with \'\-\-genconfig\'\. +. +.P +debug: Enable full debugging\. +. +.P +help: Print this help message +. +.P +verbose: Turn on verbose reporting\. +. +.P +version: Print the puppet version number and exit\.puppet queueLuke KaniesCopyright (c) 2009 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/puppetrun.8 b/man/man8/puppetrun.8 index 9cbc2bd9b..b3c27c3a7 100644 --- a/man/man8/puppetrun.8 +++ b/man/man8/puppetrun.8 @@ -1,153 +1,173 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. -. -.SH SYNOPSIS -.sp -Trigger a puppet agent run on a set of hosts. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B 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> [...]] -.UNINDENT -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -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. -.sp -If you are not storing your host configurations in LDAP, you can specify -hosts manually. -.sp -You will most likely have to run +puppet kick+ as root to get access to -the SSL certificates. -.sp -+puppet kick+ reads +puppet master+\(aqs configuration file, so that it can -copy things like LDAP settings. -.SH USAGE NOTES -.sp -+puppet kick+ is useless unless +puppet agent+ is listening. See its -documentation for more information, but the gist is that you must enable -+listen+ on the +puppet agent+ daemon, either using +\-\-listen+ on the -command line or adding \(aqlisten: true\(aq in its config file. In addition, -you need to set the daemons up to specifically allow connections by -creating the +namespaceauth+ file, normally at -\(aq/etc/puppet/namespaceauth.conf\(aq. This file specifies who has access to -each namespace; if you create the file you must add every namespace you -want any Puppet daemon to allow \-\- it is currently global to all Puppet -daemons. -.sp -An example file looks like this: -.sp +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "PUPPETRUN" "8" "August 2010" "" "" +Trigger a puppet agent run on a set of hosts\.puppet kick [\-a|\-\-all] [\-c|\-\-class \fIclass\fR] [\-d|\-\-debug] [\-f|\-\-foreground] +. +.IP "" 4 +. .nf -.ft C + + [\-h|\-\-help] [\-\-host <host>] [\-\-no\-fqdn] [\-\-ignoreschedules] + [\-t|\-\-tag <tag>] [\-\-test] [\-p|\-\-ping] <host> [<host> [\.\.\.]] +. +.fi +. +.IP "" 0 +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\. +. +.P +If you are not storing your host configurations in LDAP, you can specify hosts manually\. +. +.P +You will most likely have to run +puppet kick+ as root to get access to the SSL certificates\. +. +.P ++puppet kick+ reads +puppet master+\'s configuration file, so that it can copy things like LDAP settings\.+puppet kick+ is useless unless +puppet agent+ is listening\. See its documentation for more information, but the gist is that you must enable +listen+ on the +puppet agent+ daemon, either using +\-\-listen+ on the command line or adding \'listen: true\' in its config file\. In addition, you need to set the daemons up to specifically allow connections by creating the +namespaceauth+ file, normally at \'/etc/puppet/namespaceauth\.conf\'\. This file specifies who has access to each namespace; if you create the file you must add every namespace you want any Puppet daemon to allow \-\- it is currently global to all Puppet daemons\. +. +.P +An example file looks like this:: +. +.IP "" 4 +. +.nf + [fileserver] - allow *.madstop.com + allow *\.madstop\.com [puppetmaster] - allow *.madstop.com + allow *\.madstop\.com [puppetrunner] - allow culain.madstop.com -.ft P + allow culain\.madstop\.com +. +.fi +. +.IP "" 0 +. +.P +This is what you would install on your Puppet master; non\-master hosts could leave off the \'fileserver\' and \'puppetmaster\' namespaces\.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 \fIdirectory\fR\' as an argument\. +. +.P +See the configuration file documentation at http://reductivelabs\.com/projects/puppet/reference/configref\.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\'\. +. +.P +all: Connect to all available hosts\. Requires LDAP support +. +.IP "" 4 +. +.nf + + at this point\. +. +.fi +. +.IP "" 0 +. +.P +class: Specify a class of machines to which to connect\. This +. +.IP "" 4 +. +.nf + + only works if you have LDAP configured, at the moment\. +. +.fi +. +.IP "" 0 +. +.P +debug: Enable full debugging\. +. +.P +foreground: Run each configuration in the foreground; that is, when +. +.IP "" 4 +. +.nf + + connecting to a host, do not return until the host has + finished its run\. The default is false\. +. +.fi +. +.IP "" 0 +. +.P +help: Print this help message +. +.P +host: A specific host to which to connect\. This flag can be +. +.IP "" 4 +. +.nf + + specified more than once\. +. +.fi +. +.IP "" 0 +. +.P +ignoreschedules: Whether the client should ignore schedules when running +. +.IP "" 4 +. +.nf + + its configuration\. This can be used to force the client + to perform work it would not normally perform so soon\. + The default is false\. +. +.fi +. +.IP "" 0 +. +.P +parallel: How parallel to make the connections\. Parallelization +. +.IP "" 4 +. +.nf + + is provided by forking for each client to which to + connect\. The default is 1, meaning serial execution\. +. .fi -.sp -This is what you would install on your Puppet master; non\-master hosts -could leave off the \(aqfileserver\(aq and \(aqpuppetmaster\(aq namespaces. -.sp -Expect more documentation on this eventually. -.SH OPTIONS -.sp -Note that any configuration parameter that\(aqs valid in the configuration -file is also a valid long argument. For example, \(aqssldir\(aq is a valid -configuration parameter, so you can specify \(aq\-\-ssldir <directory>\(aq as an -argument. -.sp -See the configuration file documentation at -\fI\%http://reductivelabs.com/projects/puppet/reference/configref.html\fP for -the full list of acceptable parameters. A commented list of all -configuration options can also be generated by running puppet master -with \(aq\-\-genconfig\(aq. -.INDENT 0.0 -.TP -.B all: Connect to all available hosts. Requires LDAP support -. -at this point. -.TP -.B class: Specify a class of machines to which to connect. This -. -only works if you have LDAP configured, at the moment. -.UNINDENT -.sp -debug: Enable full debugging. -.INDENT 0.0 -.TP -.B 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. -.UNINDENT -.sp -help: Print this help message -.INDENT 0.0 -.TP -.B host: A specific host to which to connect. This flag can be -. -specified more than once. -.TP -.B 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. -.TP -.B 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. -.TP -.B tag: Specify a tag for selecting the objects to apply. Does -. -not work with the \-\-test option. -.TP -.B test: Print the hosts you would connect to but do not -. -actually connect. This option requires LDAP support at -this point. -.UNINDENT -.sp -ping: -.sp +. +.IP "" 0 +. +.P +tag: Specify a tag for selecting the objects to apply\. Does +. +.IP "" 4 +. .nf -.ft C -Do a ICMP echo against the target host. Skip hosts that don\(aqt respond to ping. -.ft P + + not work with the \-\-test option\. +. .fi -.SH EXAMPLE -.INDENT 0.0 -.INDENT 3.5 -.sp -sudo puppet kick \-p 10 \-t remotefile \-t webserver host1 host2 -.UNINDENT -.UNINDENT -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public -License -.\" Generated by docutils manpage writer. -.\" . +.IP "" 0 +. +.P +test: Print the hosts you would connect to but do not +. +.IP "" 4 +. +.nf + + actually connect\. This option requires LDAP support at + this point\. +. +.fi +. +.IP "" 0 +. +.P +ping:: +. +.P +Do a ICMP echo against the target host\. Skip hosts that don\'t respond to ping\.sudo puppet kick \-p 10 \-t remotefile \-t webserver host1 host2Luke KaniesCopyright (c) 2005 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/man/man8/ralsh.8 b/man/man8/ralsh.8 index 83494bba5..e387e2324 100644 --- a/man/man8/ralsh.8 +++ b/man/man8/ralsh.8 @@ -1,122 +1,85 @@ -.TH "" "" "" -.SH NAME - \- -.\" Man page generated from reStructeredText. -. -.SH SYNOPSIS -.sp -Use the Puppet RAL to directly interact with the system. -.SH USAGE -.INDENT 0.0 -.INDENT 3.5 -.INDENT 0.0 -.TP -.B puppet resource [\-h|\-\-help] [\-d|\-\-debug] [\-v|\-\-verbose] [\-e|\-\-edit] -. -[\-H|\-\-host <host>] [\-p|\-\-param <param>] [\-t|\-\-types] -type <name> -.UNINDENT -.UNINDENT -.UNINDENT -.SH DESCRIPTION -.sp -This command provides simple facilities for converting current system -state into Puppet code, along with some ability to use Puppet to affect -the current state. -.sp -By default, you must at least provide a type to list, which case puppet -resource will tell you everything it knows about all instances of that -type. You can optionally specify an instance name, and puppet resource -will only describe that single instance. -.sp -You can also add +\-\-edit+ as an argument, and puppet resource will write -its output to a file, open that file in an editor, and then apply the -file as a Puppet transaction. You can easily use this to use Puppet to -make simple changes to a system. -.SH OPTIONS -.sp -Note that any configuration parameter that\(aqs valid in the configuration -file is also a valid long argument. For example, \(aqssldir\(aq is a valid -configuration parameter, so you can specify \(aq\-\-ssldir <directory>\(aq as an -argument. -.sp -See the configuration file documentation at -\fI\%http://docs.puppetlabs.com/references/stable/configuration.html\fP for the -full list of acceptable parameters. A commented list of all -configuration options can also be generated by running puppet with -\(aq\-\-genconfig\(aq. -.sp -debug: Enable full debugging. -.sp +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "RALSH" "8" "August 2010" "" "" +Use the Puppet RAL to directly interact with the system\.puppet resource [\-h|\-\-help] [\-d|\-\-debug] [\-v|\-\-verbose] [\-e|\-\-edit] +. +.IP "" 4 +. +.nf + + [\-H|\-\-host <host>] [\-p|\-\-param <param>] [\-t|\-\-types] + type <name> +. +.fi +. +.IP "" 0 +This command provides simple facilities for converting current system state into Puppet code, along with some ability to use Puppet to affect the current state\. +. +.P +By default, you must at least provide a type to list, which case puppet resource will tell you everything it knows about all instances of that type\. You can optionally specify an instance name, and puppet resource will only describe that single instance\. +. +.P +You can also add +\-\-edit+ as an argument, and puppet resource will write its output to a file, open that file in an editor, and then apply the file as a Puppet transaction\. You can easily use this to use Puppet to make simple changes to a system\.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 \fIdirectory\fR\' as an argument\. +. +.P +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 with \'\-\-genconfig\'\. +. +.P +debug: Enable full debugging\. +. +.P edit: -.INDENT 0.0 -.INDENT 3.5 -.sp -Write the results of the query to a file, open the file in an editor, -and read the file back in as an executable Puppet manifest. -.UNINDENT -.UNINDENT -.sp +. +.P +Write the results of the query to a file, open the file in an editor, and read the file back in as an executable Puppet manifest\. +. +.P host: -.INDENT 0.0 -.INDENT 3.5 -.sp -When specified, connect to the resource server on the named host -and retrieve the list of resouces of the type specified. -.UNINDENT -.UNINDENT -.sp +. +.P +When specified, connect to the resource server on the named host and retrieve the list of resouces of the type specified\. +. +.P help: -.INDENT 0.0 -.INDENT 3.5 -.sp -Print this help message. -.UNINDENT -.UNINDENT -.sp +. +.P +Print this help message\. +. +.P param: -.INDENT 0.0 -.INDENT 3.5 -.sp -Add more parameters to be outputted from queries. -.UNINDENT -.UNINDENT -.sp +. +.P +Add more parameters to be outputted from queries\. +. +.P types: -.INDENT 0.0 -.INDENT 3.5 -.sp -List all available types. -.UNINDENT -.UNINDENT -.sp -verbose: Print extra information. -.SH EXAMPLE -.sp -This example uses \fBpuppet resource\fP to return Puppet configuration for -the user \fBluke\fP: -.sp +. +.P +List all available types\. +. +.P +verbose: +. +.P +Print extra information\.This example uses \fBpuppet resource\fR to return Puppet configuration for the user \fBluke\fR: +. +.IP "" 4 +. .nf -.ft C -$ puppet resource user luke -user { \(aqluke\(aq: - home => \(aq/home/luke\(aq, - uid => \(aq100\(aq, - ensure => \(aqpresent\(aq, - comment => \(aqLuke Kanies,,,\(aq, - gid => \(aq1000\(aq, - shell => \(aq/bin/bash\(aq, - groups => [\(aqsysadmin\(aq,\(aqaudio\(aq,\(aqvideo\(aq,\(aqpuppet\(aq] -} -.ft P + + $ puppet resource user luke + user { \'luke\': + home => \'/home/luke\', + uid => \'100\', + ensure => \'present\', + comment => \'Luke Kanies,,,\', + gid => \'1000\', + shell => \'/bin/bash\', + groups => [\'sysadmin\',\'audio\',\'video\',\'puppet\'] + } +. .fi -.SH AUTHOR -.sp -Luke Kanies -.SH COPYRIGHT -.sp -Copyright (c) 2005\-2007 Reductive Labs, LLC Licensed under the GNU -Public License -.\" Generated by docutils manpage writer. -.\" . +.IP "" 0 +Luke KaniesCopyright (c) 2005\-2007 Reductive Labs, LLC Licensed under the GNU Public License diff --git a/spec/fixtures/yaml/report0.25.x.yaml b/spec/fixtures/yaml/report0.25.x.yaml new file mode 100644 index 000000000..ce6a64286 --- /dev/null +++ b/spec/fixtures/yaml/report0.25.x.yaml @@ -0,0 +1,64 @@ +--- !ruby/object:Puppet::Transaction::Report + host: mattmac.local + logs: + - !ruby/object:Puppet::Util::Log + level: !ruby/sym info + message: Applying configuration version '1285283846' + source: Puppet + tags: + - info + time: 2010-09-23 16:17:26.977750 -07:00 + metrics: + time: !ruby/object:Puppet::Util::Metric + label: Time + name: time + values: + - - !ruby/sym config_retrieval + - Config retrieval + - 0.955046892166138 + - - !ruby/sym schedule + - Schedule + - 0.00123691558837891 + - - !ruby/sym total + - Total + - 0.956486701965332 + - - !ruby/sym filebucket + - Filebucket + - 0.00020289421081543 + resources: !ruby/object:Puppet::Util::Metric + label: Resources + name: resources + values: + - - !ruby/sym skipped + - Skipped + - 0 + - - !ruby/sym scheduled + - Scheduled + - 7 + - - !ruby/sym applied + - Applied + - 0 + - - !ruby/sym restarted + - Restarted + - 0 + - - !ruby/sym total + - Total + - 10 + - - !ruby/sym failed_restarts + - Failed restarts + - 0 + - - !ruby/sym out_of_sync + - Out of sync + - 0 + - - !ruby/sym failed + - Failed + - 0 + changes: !ruby/object:Puppet::Util::Metric + label: Changes + name: changes + values: + - - !ruby/sym total + - Total + - 0 + records: {} + time: 2010-09-23 16:17:26.987789 -07:00
\ No newline at end of file diff --git a/spec/fixtures/yaml/report2.6.x.yaml b/spec/fixtures/yaml/report2.6.x.yaml new file mode 100644 index 000000000..dd4c3814e --- /dev/null +++ b/spec/fixtures/yaml/report2.6.x.yaml @@ -0,0 +1,190 @@ +--- !ruby/object:Puppet::Transaction::Report + external_times: + !ruby/sym config_retrieval: 0.170313835144043 + host: ubuntu1004desktop.localdomain + logs: + - !ruby/object:Puppet::Util::Log + level: !ruby/sym debug + message: Using cached certificate for ca + source: Puppet + tags: + - debug + time: 2010-09-23 15:44:06.244173 -07:00 + version: &id001 2.6.1 + - !ruby/object:Puppet::Util::Log + level: !ruby/sym debug + message: Using cached certificate for ubuntu1004desktop.localdomain + source: Puppet + tags: + - debug + time: 2010-09-23 15:44:06.244764 -07:00 + version: *id001 + - !ruby/object:Puppet::Util::Log + level: !ruby/sym debug + message: Using cached certificate_revocation_list for ca + source: Puppet + tags: + - debug + time: 2010-09-23 15:44:06.245677 -07:00 + version: *id001 + - !ruby/object:Puppet::Util::Log + level: !ruby/sym debug + message: "catalog supports formats: b64_zlib_yaml dot marshal pson raw yaml; using pson" + source: Puppet + tags: + - debug + time: 2010-09-23 15:44:06.247069 -07:00 + version: *id001 + - !ruby/object:Puppet::Util::Log + level: !ruby/sym info + message: Caching catalog for ubuntu1004desktop.localdomain + source: Puppet + tags: + - info + time: 2010-09-23 15:44:06.409109 -07:00 + version: *id001 + - !ruby/object:Puppet::Util::Log + level: !ruby/sym debug + message: Creating default schedules + source: Puppet + tags: + - debug + time: 2010-09-23 15:44:06.418755 -07:00 + version: *id001 + - !ruby/object:Puppet::Util::Log + level: !ruby/sym debug + message: Loaded state in 0.00 seconds + source: Puppet + tags: + - debug + time: 2010-09-23 15:44:06.427441 -07:00 + version: *id001 + - !ruby/object:Puppet::Util::Log + level: !ruby/sym info + message: Applying configuration version '1285281846' + source: Puppet + tags: + - info + time: 2010-09-23 15:44:06.429532 -07:00 + version: *id001 + metrics: + time: !ruby/object:Puppet::Util::Metric + label: Time + name: time + values: + - - config_retrieval + - Config retrieval + - 0.170313835144043 + - - schedule + - Schedule + - 0.00077 + - - filebucket + - Filebucket + - 0.000166 + resources: !ruby/object:Puppet::Util::Metric + label: Resources + name: resources + values: + - - !ruby/sym total + - Total + - 7 + events: !ruby/object:Puppet::Util::Metric + label: Events + name: events + values: + - - !ruby/sym total + - Total + - 0 + changes: !ruby/object:Puppet::Util::Metric + label: Changes + name: changes + values: + - - !ruby/sym total + - Total + - 0 + resource_statuses: + "Schedule[monthly]": !ruby/object:Puppet::Resource::Status + evaluation_time: 0.000121 + events: [] + file: + line: + resource: "Schedule[monthly]" + source_description: "/Schedule[monthly]" + tags: + - schedule + - monthly + time: 2010-09-23 15:44:06.430577 -07:00 + version: 1285281846 + "Filebucket[puppet]": !ruby/object:Puppet::Resource::Status + evaluation_time: 0.000166 + events: [] + file: + line: + resource: "Filebucket[puppet]" + source_description: "/Filebucket[puppet]" + tags: + - filebucket + - puppet + time: 2010-09-23 15:44:06.430998 -07:00 + version: 1285281846 + "Schedule[never]": !ruby/object:Puppet::Resource::Status + evaluation_time: 0.000119 + events: [] + file: + line: + resource: "Schedule[never]" + source_description: "/Schedule[never]" + tags: + - schedule + - never + time: 2010-09-23 15:44:06.433034 -07:00 + version: 1285281846 + "Schedule[weekly]": !ruby/object:Puppet::Resource::Status + evaluation_time: 0.000118 + events: [] + file: + line: + resource: "Schedule[weekly]" + source_description: "/Schedule[weekly]" + tags: + - schedule + - weekly + time: 2010-09-23 15:44:06.431443 -07:00 + version: 1285281846 + "Schedule[puppet]": !ruby/object:Puppet::Resource::Status + evaluation_time: 0.000129 + events: [] + file: + line: + resource: "Schedule[puppet]" + source_description: "/Schedule[puppet]" + tags: + - schedule + - puppet + time: 2010-09-23 15:44:06.432626 -07:00 + version: 1285281846 + "Schedule[daily]": !ruby/object:Puppet::Resource::Status + evaluation_time: 0.000154 + events: [] + file: + line: + resource: "Schedule[daily]" + source_description: "/Schedule[daily]" + tags: + - schedule + - daily + time: 2010-09-23 15:44:06.430130 -07:00 + version: 1285281846 + "Schedule[hourly]": !ruby/object:Puppet::Resource::Status + evaluation_time: 0.000129 + events: [] + file: + line: + resource: "Schedule[hourly]" + source_description: "/Schedule[hourly]" + tags: + - schedule + - hourly + time: 2010-09-23 15:44:06.432185 -07:00 + version: 1285281846 + time: 2010-09-23 15:44:05.894401 -07:00
\ No newline at end of file diff --git a/spec/integration/application/doc_spec.rb b/spec/integration/application/doc_spec.rb new file mode 100644 index 000000000..eaf5442a0 --- /dev/null +++ b/spec/integration/application/doc_spec.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet_spec/files' + +describe Puppet::Application::Doc do + include PuppetSpec::Files + + it "should not generate an error when module dir overlaps parent of site.pp (#4798)" do + begin + # Note: the directory structure below is more complex than it + # needs to be, but it's representative of the directory structure + # used in bug #4798. + old_dir = Dir.getwd # Note: can't use chdir with a block because it will generate bogus warnings + tmpdir = tmpfile('doc_spec') + Dir.mkdir(tmpdir) + Dir.chdir(tmpdir) + site_file = 'site.pp' + File.open(site_file, 'w') do |f| + f.puts '# A comment' + end + modules_dir = 'modules' + Dir.mkdir(modules_dir) + rt_dir = File.join(modules_dir, 'rt') + Dir.mkdir(rt_dir) + manifests_dir = File.join(rt_dir, 'manifests') + Dir.mkdir(manifests_dir) + rt_file = File.join(manifests_dir, 'rt.pp') + File.open(rt_file, 'w') do |f| + f.puts '# A class' + f.puts 'class foo { }' + f.puts '# A definition' + f.puts 'define bar { }' + end + + puppet = Puppet::Application[:doc] + Puppet[:modulepath] = modules_dir + Puppet[:manifest] = site_file + puppet.options[:mode] = :rdoc + puppet.expects(:exit).with(0) + puppet.run_command + + File.should be_exist('doc') + ensure + Dir.chdir(old_dir) + end + end + + it "should respect the -o option" do + puppetdoc = Puppet::Application[:doc] + puppetdoc.command_line.stubs(:args).returns(['foo', '-o', 'bar']) + puppetdoc.parse_options + puppetdoc.options[:outputdir].should == 'bar' + end +end diff --git a/spec/integration/configurer_spec.rb b/spec/integration/configurer_spec.rb index 9a8b66fe4..cb7d3d779 100755 --- a/spec/integration/configurer_spec.rb +++ b/spec/integration/configurer_spec.rb @@ -5,6 +5,8 @@ require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/configurer' describe Puppet::Configurer do + include PuppetSpec::Files + describe "when downloading plugins" do it "should use the :pluginsignore setting, split on whitespace, for ignoring remote files" do resource = Puppet::Type.type(:notify).new :name => "yay" @@ -17,19 +19,50 @@ describe Puppet::Configurer do end describe "when running" do - it "should send a transaction report with valid data" do - catalog = Puppet::Resource::Catalog.new - catalog.add_resource(Puppet::Type.type(:notify).new(:title => "testing")) + before(:each) do + @catalog = Puppet::Resource::Catalog.new + @catalog.add_resource(Puppet::Type.type(:notify).new(:title => "testing")) - configurer = Puppet::Configurer.new + # Make sure we don't try to persist the local state after the transaction ran, + # because it will fail during test (the state file is in an not existing directory) + # and we need the transaction to be successful to be able to produce a summary report + @catalog.host_config = false + + @configurer = Puppet::Configurer.new + end + + it "should send a transaction report with valid data" do + @configurer.stubs(:save_last_run_summary) Puppet::Transaction::Report.indirection.expects(:save).with do |x, report| report.time.class == Time and report.logs.length > 0 end Puppet[:report] = true - configurer.run :catalog => catalog + @configurer.run :catalog => @catalog + end + + it "should save a correct last run summary" do + report = Puppet::Transaction::Report.new + report.stubs(:save) + + Puppet[:lastrunfile] = tmpfile("lastrunfile") + Puppet[:report] = true + + @configurer.run :catalog => @catalog, :report => report + + summary = nil + File.open(Puppet[:lastrunfile], "r") do |fd| + summary = YAML.load(fd.read) + end + + summary.should be_a(Hash) + %w{time changes events resources}.each do |key| + summary.should be_key(key) + end + summary["time"].should be_key("notify") + summary["time"]["last_run"].should >= Time.now.tv_sec end end end diff --git a/spec/integration/defaults_spec.rb b/spec/integration/defaults_spec.rb index 4ae2983f4..2f30014e8 100755 --- a/spec/integration/defaults_spec.rb +++ b/spec/integration/defaults_spec.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/defaults' +require 'puppet/rails' describe "Puppet defaults" do include Puppet::Util::Execution @@ -227,7 +228,7 @@ describe "Puppet defaults" do it "should have a :caname setting that defaults to the cert name" do Puppet.settings[:certname] = "foo" - Puppet.settings[:ca_name].should == "foo" + Puppet.settings[:ca_name].should == "Puppet CA: foo" end it "should have a 'prerun_command' that defaults to the empty string" do diff --git a/spec/integration/indirector/bucket_file/rest_spec.rb b/spec/integration/indirector/bucket_file/rest_spec.rb deleted file mode 100644 index 4d90a8c59..000000000 --- a/spec/integration/indirector/bucket_file/rest_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/file_bucket/file' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Filebucket REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - ca.generate("foo.madstop.com") unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @host = Puppet::SSL::Host.new(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :file_bucket_file ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - @old_terminus = Puppet::FileBucket::File.indirection.terminus_class - Puppet::FileBucket::File.terminus_class = :rest - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @file_bucket_file = stub_everything 'file_bucket_file' - @mock_model = stub('faked model', :name => "file_bucket_file", :convert_from => @file_bucket_file) - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - Puppet::FileBucket::File.terminus_class = @old_terminus - end - - it "should be able save a file to the remote filebucket" do - @file_bucket_file.expects(:save) - - file_bucket_file = Puppet::FileBucket::File.new("pouet") - file_bucket_file.save - end -end diff --git a/spec/integration/indirector/certificate/rest_spec.rb b/spec/integration/indirector/certificate/rest_spec.rb deleted file mode 100755 index 356a7d316..000000000 --- a/spec/integration/indirector/certificate/rest_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/ssl/certificate' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Certificate REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - ca.generate("foo.madstop.com") unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @host = Puppet::SSL::Host.new(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :certificate ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # Then switch to a remote CA, so that we go through REST. - Puppet::SSL::Host.ca_location = :remote - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "certificate") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization).returns(true) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - end - - it "should be able to retrieve a remote certificate" do - @mock_model.expects(:find).returns @host.certificate - result = Puppet::SSL::Certificate.find('bar') - - # There's no good '==' method on certs. - result.content.to_s.should == @host.certificate.content.to_s - result.name.should == "bar" - end -end diff --git a/spec/integration/indirector/certificate_request/rest_spec.rb b/spec/integration/indirector/certificate_request/rest_spec.rb deleted file mode 100755 index 2c98ef66c..000000000 --- a/spec/integration/indirector/certificate_request/rest_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/ssl/certificate_request' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Certificate Request REST Terminus" do - before do - Puppet::Util::Cacher.expire - - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - # Create the CSR and write it to disk - @host = Puppet::SSL::Host.new("foo.madstop.com") - @host.generate_certificate_request - - # Now remove the cached csr - Puppet::SSL::Host.ca_location = :none - Puppet::SSL::Host.destroy("foo.madstop.com") - - @params = { :port => 34343, :handlers => [ :certificate_request ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # Then switch to a remote CA, so that we go through REST. - Puppet::SSL::Host.ca_location = :remote - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "certificate request") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization).returns(true) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - end - - it "should be able to save a certificate request to the CA" do - key = Puppet::SSL::Key.new("bar.madstop.com") - key.generate - - csr = Puppet::SSL::CertificateRequest.new("bar.madstop.com") - csr.generate(key.content) - - server_csr = mock 'csr' - server_csr.expects(:save) - @mock_model.expects(:convert_from).with("s", csr.content.to_s).returns server_csr - - csr.save - end - - it "should be able to retrieve a remote certificate request" do - # We're finding the cached value :/ - @mock_model.expects(:find).returns @host.certificate_request - result = Puppet::SSL::CertificateRequest.find('foo.madstop.com') - - # There's no good '==' method on certs. - result.content.to_s.should == @host.certificate_request.content.to_s - result.name.should == @host.certificate_request.name - end -end diff --git a/spec/integration/indirector/certificate_revocation_list/rest_spec.rb b/spec/integration/indirector/certificate_revocation_list/rest_spec.rb deleted file mode 100755 index 62a2f808e..000000000 --- a/spec/integration/indirector/certificate_revocation_list/rest_spec.rb +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/ssl/certificate' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Certificate REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :certificate_revocation_list ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # And make sure we've generated the CRL - @crl = ca.crl - - # Now remove the cached crl - Puppet::SSL::Host.ca_location = :none - Puppet::SSL::CertificateRevocationList.destroy(Puppet::SSL::CA_NAME) - - # This is necessary so that we create the SSL store before we start - # using REST. This is necessary to prevent an infinite loop, - # which only occurs during testing. - Puppet::Network::HttpPool.ssl_host.ssl_store - - # Then switch to a remote CA, so that we go through REST. - Puppet::SSL::Host.ca_location = :remote - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "certificate") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization).returns(true) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - end - - it "should be able to retrieve a remote CRL" do - @mock_model.expects(:find).returns @crl - result = Puppet::SSL::CertificateRevocationList.find('bar') - - # There's no good '==' method on certs. - result.content.to_s.should == @crl.content.to_s - end -end diff --git a/spec/integration/indirector/report/rest_spec.rb b/spec/integration/indirector/report/rest_spec.rb deleted file mode 100644 index 089f8fd3f..000000000 --- a/spec/integration/indirector/report/rest_spec.rb +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/transaction/report' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Report REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - ca.generate("foo.madstop.com") unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @host = Puppet::SSL::Host.new(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :report ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # Let's use REST for our reports :-) - @old_terminus = Puppet::Transaction::Report.indirection.terminus_class - Puppet::Transaction::Report.terminus_class = :rest - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'save', which would cause an immediate - # return. - @report = stub_everything 'report' - @mock_model = stub_everything 'faked model', :name => "report", :convert_from => @report - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - Puppet::Transaction::Report.terminus_class = @old_terminus - end - - it "should be able to send a report to the server" do - @report.expects(:save) - - report = Puppet::Transaction::Report.new - - resourcemetrics = { - :total => 12, - :out_of_sync => 20, - :applied => 45, - :skipped => 1, - :restarted => 23, - :failed_restarts => 1, - :scheduled => 10 - } - report.add_metric(:resources, resourcemetrics) - - timemetrics = { - :resource1 => 10, - :resource2 => 50, - :resource3 => 40, - :resource4 => 20, - } - report.add_metric(:times, timemetrics) - - - report.add_metric( - :changes, - - :total => 20 - ) - - report.save - end -end diff --git a/spec/integration/indirector/rest_spec.rb b/spec/integration/indirector/rest_spec.rb deleted file mode 100755 index e9048392a..000000000 --- a/spec/integration/indirector/rest_spec.rb +++ /dev/null @@ -1,524 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../../spec_helper' -require 'puppet/network/server' -require 'puppet/indirector' -require 'puppet/indirector/rest' - -# a fake class that will be indirected via REST -class Puppet::TestIndirectedFoo - extend Puppet::Indirector - indirects :test_indirected_foo, :terminus_setting => :test_indirected_foo_terminus - - attr_reader :value - attr_accessor :name - - def initialize(value = 0) - @value = value - end - - def self.from_yaml(yaml) - YAML.load(yaml) - end - - def name - "bob" - end -end - -# empty Terminus class -- this would normally have to be in a directory findable by the autoloader, but we short-circuit that below -class Puppet::TestIndirectedFoo::Rest < Puppet::Indirector::REST -end - - -describe Puppet::Indirector::REST do - before do - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::SSL::Host.ca_location = :local - - Puppet::TestIndirectedFoo.terminus_class = :rest - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - end - - describe "when using webrick" do - before :each do - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :test_indirected_foo ], :xmlrpc_handlers => [ :status ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "foo") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - # do not trigger the authorization layer - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization).returns(true) - end - - describe "when finding a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @model_instance = Puppet::TestIndirectedFoo.new(23) - @mock_model.stubs(:find).returns @model_instance - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error - end - - it 'should return an instance of the model class' do - Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo - end - - it "should pass options all the way through" do - @mock_model.expects(:find).with { |key, args| args[:one] == "two" and args[:three] == "four" }.returns @model_instance - Puppet::TestIndirectedFoo.find('bar', :one => "two", :three => "four") - end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value - end - - it 'should set an expiration on model instance' do - Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil - end - - it "should use a supported format" do - Puppet::TestIndirectedFoo.expects(:supported_formats).returns ["marshal"] - text = Marshal.dump(@model_instance) - @model_instance.expects(:render).with(Puppet::Network::FormatHandler.format("marshal")).returns text - Puppet::TestIndirectedFoo.find('bar') - end - end - - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :name => "foo", :find => nil) - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return nil" do - Puppet::TestIndirectedFoo.find('bar').should be_nil - end - end - - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model = stub('faked model', :name => "foo") - @mock_model.stubs(:find).raises(RuntimeError) - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(Net::HTTPError) - end - end - end - - describe "when searching for model instances over REST" do - describe "when matching model instances can be found" do - before :each do - @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ] - @mock_model.stubs(:search).returns @model_instances - - # Force yaml, because otherwise our mocks can't work correctly - Puppet::TestIndirectedFoo.stubs(:supported_formats).returns %w{yaml} - - @mock_model.stubs(:render_multiple).returns @model_instances.to_yaml - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error - end - - it 'should return all matching results' do - Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length - end - - it "should pass options all the way through" do - @mock_model.expects(:search).with { |key, args| args[:one] == "two" and args[:three] == "four" }.returns @model_instances - Puppet::TestIndirectedFoo.search("foo", :one => "two", :three => "four") - end - - it 'should return model instances' do - Puppet::TestIndirectedFoo.search('bar').each do |result| - result.class.should == Puppet::TestIndirectedFoo - end - end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.search('bar').collect { |i| i.value }.should == @model_instances.collect { |i| i.value } - end - end - - describe "when no matching model instance can be found" do - before :each do - @mock_model = stub('faked model', :name => "foo", :find => nil) - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - end - - it "should return nil" do - Puppet::TestIndirectedFoo.find('bar').should be_nil - end - end - - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model = stub('faked model') - @mock_model.stubs(:find).raises(RuntimeError) - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(Net::HTTPError) - end - end - end - - describe "when destroying a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @mock_model.stubs(:destroy).returns true - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error - end - - it 'should return success' do - Puppet::TestIndirectedFoo.destroy('bar').should == true - end - end - - describe "when no matching model instance can be found" do - before :each do - @mock_model.stubs(:destroy).returns false - end - - it "should return failure" do - Puppet::TestIndirectedFoo.destroy('bar').should == false - end - end - - describe "when an exception is encountered in destroying a model instance" do - before :each do - @mock_model.stubs(:destroy).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(Net::HTTPError) - end - end - end - - describe "when saving a model instance over REST" do - before :each do - @instance = Puppet::TestIndirectedFoo.new(42) - @mock_model.stubs(:save_object).returns @instance - @mock_model.stubs(:convert_from).returns @instance - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(@instance) - end - - describe "when a successful save can be performed" do - before :each do - end - - it "should not fail" do - lambda { @instance.save }.should_not raise_error - end - - it 'should return an instance of the model class' do - @instance.save.class.should == Puppet::TestIndirectedFoo - end - - it 'should return a matching instance of the model class' do - @instance.save.value.should == @instance.value - end - end - - describe "when a save cannot be completed" do - before :each do - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).returns(false) - end - - it "should return failure" do - @instance.save.should == false - end - end - - describe "when an exception is encountered in performing a save" do - before :each do - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:save_object).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { @instance.save }.should raise_error(Net::HTTPError) - end - end - end - - after :each do - @server.unlisten - end - end - - describe "when using mongrel" do - confine "Mongrel is not available" => Puppet.features.mongrel? - - before :each do - Puppet[:servertype] = 'mongrel' - @params = { :port => 34343, :handlers => [ :test_indirected_foo ] } - - # Make sure we never get a cert, since mongrel can't speak ssl - Puppet::SSL::Certificate.stubs(:find).returns nil - - # We stub ssl to be off, since mongrel can't speak ssl - Net::HTTP.any_instance.stubs(:use_ssl?).returns false - - @server = Puppet::Network::Server.new(@params) - @server.listen - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "foo") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - # do not trigger the authorization layer - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:check_authorization).returns(true) - end - - after do - @server.unlisten - end - - describe "when finding a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @model_instance = Puppet::TestIndirectedFoo.new(23) - @mock_model.stubs(:find).returns @model_instance - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should_not raise_error - end - - it 'should return an instance of the model class' do - Puppet::TestIndirectedFoo.find('bar').class.should == Puppet::TestIndirectedFoo - end - - it "should pass options all the way through" do - @mock_model.expects(:find).with { |key, args| args[:one] == "two" and args[:three] == "four" }.returns @model_instance - Puppet::TestIndirectedFoo.find('bar', :one => "two", :three => "four") - end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.find('bar').value.should == @model_instance.value - end - - it 'should set an expiration on model instance' do - Puppet::TestIndirectedFoo.find('bar').expiration.should_not be_nil - end - - it "should use a supported format" do - Puppet::TestIndirectedFoo.expects(:supported_formats).returns ["marshal"] - format = stub 'format' - text = Marshal.dump(@model_instance) - @model_instance.expects(:render).with(Puppet::Network::FormatHandler.format("marshal")).returns text - Puppet::TestIndirectedFoo.find('bar') - end - end - - describe "when no matching model instance can be found" do - before :each do - @mock_model.stubs(:find).returns nil - end - - it "should return nil" do - Puppet::TestIndirectedFoo.find('bar').should be_nil - end - end - - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model.stubs(:find).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(Net::HTTPError) - end - end - end - - describe "when searching for model instances over REST" do - describe "when matching model instances can be found" do - before :each do - @model_instances = [ Puppet::TestIndirectedFoo.new(23), Puppet::TestIndirectedFoo.new(24) ] - - # Force yaml, because otherwise our mocks can't work correctly - Puppet::TestIndirectedFoo.stubs(:supported_formats).returns %w{yaml} - - @mock_model.stubs(:search).returns @model_instances - @mock_model.stubs(:render_multiple).returns @model_instances.to_yaml - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.search('bar') }.should_not raise_error - end - - it 'should return all matching results' do - Puppet::TestIndirectedFoo.search('bar').length.should == @model_instances.length - end - - it "should pass options all the way through" do - @mock_model.expects(:search).with { |key, args| args[:one] == "two" and args[:three] == "four" }.returns @model_instances - Puppet::TestIndirectedFoo.search('bar', :one => "two", :three => "four") - end - - it 'should return model instances' do - Puppet::TestIndirectedFoo.search('bar').each do |result| - result.class.should == Puppet::TestIndirectedFoo - end - end - - it 'should return the instance of the model class associated with the provided lookup key' do - Puppet::TestIndirectedFoo.search('bar').collect { |i| i.value }.should == @model_instances.collect { |i| i.value } - end - - it 'should set an expiration on model instances' do - Puppet::TestIndirectedFoo.search('bar').each do |result| - result.expiration.should_not be_nil - end - end - end - - describe "when no matching model instance can be found" do - before :each do - @mock_model.stubs(:search).returns nil - @mock_model.stubs(:render_multiple).returns nil.to_yaml - end - - it "should return nil" do - Puppet::TestIndirectedFoo.search('bar').should == [] - end - end - - describe "when an exception is encountered in looking up a model instance" do - before :each do - @mock_model.stubs(:find).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.find('bar') }.should raise_error(Net::HTTPError) - end - end - end - - describe "when destroying a model instance over REST" do - describe "when a matching model instance can be found" do - before :each do - @mock_model.stubs(:destroy).returns true - end - - it "should not fail" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should_not raise_error - end - - it 'should return success' do - Puppet::TestIndirectedFoo.destroy('bar').should == true - end - end - - describe "when no matching model instance can be found" do - before :each do - @mock_model.stubs(:destroy).returns false - end - - it "should return failure" do - Puppet::TestIndirectedFoo.destroy('bar').should == false - end - end - - describe "when an exception is encountered in destroying a model instance" do - before :each do - @mock_model.stubs(:destroy).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { Puppet::TestIndirectedFoo.destroy('bar') }.should raise_error(Net::HTTPError) - end - end - end - - describe "when saving a model instance over REST" do - before :each do - @instance = Puppet::TestIndirectedFoo.new(42) - @mock_model.stubs(:convert_from).returns @instance - - # LAK:NOTE This stub is necessary to prevent the REST call from calling - # REST.save again, thus producing painful infinite recursion. - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(@instance) - end - - describe "when a successful save can be performed" do - before :each do - end - - it "should not fail" do - lambda { @instance.save }.should_not raise_error - end - - it 'should return an instance of the model class' do - @instance.save.class.should == Puppet::TestIndirectedFoo - end - - it 'should return a matching instance of the model class' do - @instance.save.value.should == @instance.value - end - end - - describe "when a save cannot be completed" do - before :each do - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).returns(false) - end - - it "should return failure" do - @instance.save.should == false - end - end - - describe "when an exception is encountered in performing a save" do - before :each do - Puppet::Network::HTTP::MongrelREST.any_instance.stubs(:save_object).raises(RuntimeError) - end - - it "should raise an exception" do - lambda { @instance.save }.should raise_error(Net::HTTPError) - end - end - end - end -end diff --git a/spec/integration/network/server/webrick_spec.rb b/spec/integration/network/server/webrick_spec.rb index 2809df780..2b14dfb37 100755 --- a/spec/integration/network/server/webrick_spec.rb +++ b/spec/integration/network/server/webrick_spec.rb @@ -18,6 +18,7 @@ describe Puppet::Network::Server do Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir + Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local diff --git a/spec/integration/parser/collector_spec.rb b/spec/integration/parser/collector_spec.rb index 73273c909..b1cfc51c7 100755 --- a/spec/integration/parser/collector_spec.rb +++ b/spec/integration/parser/collector_spec.rb @@ -17,7 +17,7 @@ describe Puppet::Parser::Collector do def query(text) code = "File <| #{text} |>" parser = Puppet::Parser::Parser.new(@scope.compiler) - parser.parse(code).hostclass("").code[0].query + return parser.parse(code).code[0].query end {true => [%{title == "/tmp/testing"}, %{(title == "/tmp/testing")}, %{group == bin}, diff --git a/spec/integration/parser/compiler_spec.rb b/spec/integration/parser/compiler_spec.rb index 83bbf9500..f731692b3 100755 --- a/spec/integration/parser/compiler_spec.rb +++ b/spec/integration/parser/compiler_spec.rb @@ -26,4 +26,109 @@ describe Puppet::Parser::Compiler do @compiler.catalog.version.should == version end + + it "should not create duplicate resources when a class is referenced both directly and indirectly by the node classifier (4792)" do + Puppet[:code] = <<-PP + class foo + { + notify { foo_notify: } + include bar + } + class bar + { + notify { bar_notify: } + } + PP + + @node.stubs(:classes).returns(['foo', 'bar']) + + catalog = Puppet::Parser::Compiler.compile(@node) + + catalog.resource("Notify[foo_notify]").should_not be_nil + catalog.resource("Notify[bar_notify]").should_not be_nil + end + + describe "when resolving class references" do + it "should favor local scope, even if there's an included class in topscope" do + Puppet[:code] = <<-PP + class experiment { + class baz { + } + notify {"x" : require => Class[Baz] } + } + class baz { + } + include baz + include experiment + include experiment::baz + PP + + catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) + + notify_resource = catalog.resource( "Notify[x]" ) + + notify_resource[:require].title.should == "Experiment::Baz" + end + + it "should favor local scope, even if there's an unincluded class in topscope" do + Puppet[:code] = <<-PP + class experiment { + class baz { + } + notify {"x" : require => Class[Baz] } + } + class baz { + } + include experiment + include experiment::baz + PP + + catalog = Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) + + notify_resource = catalog.resource( "Notify[x]" ) + + notify_resource[:require].title.should == "Experiment::Baz" + end + end + + it "should recompute the version after input files are re-parsed" do + Puppet[:code] = 'class foo { }' + Time.stubs(:now).returns(1) + node = Puppet::Node.new('mynode') + Puppet::Parser::Compiler.compile(node).version.should == 1 + Time.stubs(:now).returns(2) + Puppet::Parser::Compiler.compile(node).version.should == 1 # no change because files didn't change + Puppet::Resource::TypeCollection.any_instance.stubs(:stale?).returns(true).then.returns(false) # pretend change + Puppet::Parser::Compiler.compile(node).version.should == 2 + end + + ['class', 'define', 'node'].each do |thing| + it "should not allow #{thing} inside evaluated conditional constructs" do + Puppet[:code] = <<-PP + if true { + #{thing} foo { + } + notify { decoy: } + } + PP + + begin + Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) + raise "compilation should have raised Puppet::Error" + rescue Puppet::Error => e + e.message.should =~ /at line 2/ + end + end + end + + it "should not allow classes inside unevaluated conditional constructs" do + Puppet[:code] = <<-PP + if false { + class foo { + } + } + PP + + lambda { Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) }.should raise_error(Puppet::Error) + end end diff --git a/spec/integration/parser/functions_spec.rb b/spec/integration/parser/functions_spec.rb new file mode 100644 index 000000000..cbfb4ac88 --- /dev/null +++ b/spec/integration/parser/functions_spec.rb @@ -0,0 +1,21 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +describe Puppet::Parser::Functions do + before :each do + Puppet::Parser::Functions.rmfunction("template") if Puppet::Parser::Functions.function("template") + end + + it "should support multiple threads autoloading the same function" do + threads = [] + lambda { + 10.times { |a| + threads << Thread.new { + Puppet::Parser::Functions.function("template") + } + } + }.should_not raise_error + threads.each { |t| t.join } + end +end
\ No newline at end of file diff --git a/spec/integration/parser/parser_spec.rb b/spec/integration/parser/parser_spec.rb index 7b85bcacb..0d9aa51e1 100755 --- a/spec/integration/parser/parser_spec.rb +++ b/spec/integration/parser/parser_spec.rb @@ -11,7 +11,7 @@ describe Puppet::Parser::Parser do end def result_instance - @result.hostclass("").code[0] + @result.code[0] end def matches?(string) @@ -44,7 +44,7 @@ describe Puppet::Parser::Parser do end def result_instance - @result.hostclass("").code[0] + @result.code[0] end def matches?(string) @@ -85,7 +85,9 @@ describe Puppet::Parser::Parser do class test {} """) - ast.hostclass("test").doc.should == "comment\n" + ast.code[0].should be_a(Puppet::Parser::AST::Hostclass) + ast.code[0].name.should == 'test' + ast.code[0].instantiate('')[0].doc.should == "comment\n" end end diff --git a/spec/integration/parser/ruby_manifest_spec.rb b/spec/integration/parser/ruby_manifest_spec.rb new file mode 100644 index 000000000..de6f4628c --- /dev/null +++ b/spec/integration/parser/ruby_manifest_spec.rb @@ -0,0 +1,128 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'tempfile' +require 'puppet_spec/files' + +describe "Pure ruby manifests" do + include PuppetSpec::Files + + before do + @node = Puppet::Node.new "testnode" + + @scope_resource = stub 'scope_resource', :builtin? => true, :finish => nil, :ref => 'Class[main]' + @scope = stub 'scope', :resource => @scope_resource, :source => mock("source") + @test_dir = tmpdir('ruby_manifest_test') + end + + after do + Puppet.settings.clear + end + + def write_file(name, contents) + path = File.join(@test_dir, name) + File.open(path, "w") { |f| f.write(contents) } + path + end + + def compile(contents) + Puppet[:code] = contents + Dir.chdir(@test_dir) do + Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) + end + end + + it "should allow classes" do + write_file('foo.rb', ["hostclass 'one' do notify('one_notify') end", + "hostclass 'two' do notify('two_notify') end"].join("\n")) + catalog = compile("import 'foo'\ninclude one") + catalog.resource("Notify[one_notify]").should_not be_nil + catalog.resource("Notify[two_notify]").should be_nil + end + + it "should allow defines" do + write_file('foo.rb', 'define "bar", :arg do notify("bar_#{@name}_#{@arg}") end') + catalog = compile("import 'foo'\nbar { instance: arg => 'xyz' }") + catalog.resource("Notify[bar_instance_xyz]").should_not be_nil + catalog.resource("Bar[instance]").should_not be_nil + end + + it "should allow node declarations" do + write_file('foo.rb', "node 'mynode' do notify('mynode') end") + catalog = compile("import 'foo'") + node_declaration = catalog.resource("Notify[mynode]") + node_declaration.should_not be_nil + node_declaration.title.should == 'mynode' + end + + it "should allow access to the environment" do + write_file('foo.rb', ["hostclass 'bar' do", + " if environment.is_a? Puppet::Node::Environment", + " notify('success')", + " end", + "end"].join("\n")) + compile("import 'foo'\ninclude bar").resource("Notify[success]").should_not be_nil + end + + it "should allow creation of resources of built-in types" do + write_file('foo.rb', "hostclass 'bar' do file 'test_file', :owner => 'root', :mode => '644' end") + catalog = compile("import 'foo'\ninclude bar") + file = catalog.resource("File[test_file]") + file.should be_a(Puppet::Resource) + file.type.should == 'File' + file.title.should == 'test_file' + file.exported.should_not be + file.virtual.should_not be + file[:owner].should == 'root' + file[:mode].should == '644' + file[:stage].should be_nil # TODO: is this correct behavior? + end + + it "should allow calling user-defined functions" do + write_file('foo.rb', "hostclass 'bar' do user_func 'name', :arg => 'xyz' end") + catalog = compile(['define user_func($arg) { notify {"n_$arg": } }', + 'import "foo"', + 'include bar'].join("\n")) + catalog.resource("Notify[n_xyz]").should_not be_nil + catalog.resource("User_func[name]").should_not be_nil + end + + it "should be properly cached for multiple compiles" do + # Note: we can't test this by calling compile() twice, because + # that sets Puppet[:code], which clears out all cached + # environments. + Puppet[:filetimeout] = 1000 + write_file('foo.rb', "hostclass 'bar' do notify('success') end") + Puppet[:code] = "import 'foo'\ninclude bar" + + # Compile the catalog and check it + catalog = Dir.chdir(@test_dir) do + Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) + end + catalog.resource("Notify[success]").should_not be_nil + + # Secretly change the file to make it invalid. This change + # shouldn't be noticed because the we've set a high + # Puppet[:filetimeout]. + write_file('foo.rb', "raise 'should not be executed'") + + # Compile the catalog a second time and make sure it's still ok. + catalog = Dir.chdir(@test_dir) do + Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) + end + catalog.resource("Notify[success]").should_not be_nil + end + + it "should be properly reloaded when stale" do + Puppet[:filetimeout] = -1 # force stale check to happen all the time + write_file('foo.rb', "hostclass 'bar' do notify('version1') end") + catalog = compile("import 'foo'\ninclude bar") + catalog.resource("Notify[version1]").should_not be_nil + sleep 1 # so that timestamp will change forcing file reload + write_file('foo.rb', "hostclass 'bar' do notify('version2') end") + catalog = compile("import 'foo'\ninclude bar") + catalog.resource("Notify[version1]").should be_nil + catalog.resource("Notify[version2]").should_not be_nil + end +end diff --git a/spec/integration/provider/mailalias/aliases_spec.rb b/spec/integration/provider/mailalias/aliases_spec.rb index 8106c2cb5..0511205f2 100755 --- a/spec/integration/provider/mailalias/aliases_spec.rb +++ b/spec/integration/provider/mailalias/aliases_spec.rb @@ -2,7 +2,6 @@ require File.dirname(__FILE__) + '/../../../spec_helper' -require 'puppettest' require 'puppettest/support/utils' require 'puppettest/fileparsing' @@ -11,15 +10,16 @@ provider_class = Puppet::Type.type(:mailalias).provider(:aliases) describe provider_class do include PuppetTest include PuppetTest::FileParsing + include PuppetTest::Support::Utils before :each do @provider = provider_class end # #1560 - PuppetTest.fakedata("data/providers/mailalias/aliases").each { |file| - it "should be able to parse the examples in #{file}" do + it "should be able to parse the mailalias examples" do + fakedata("data/providers/mailalias/aliases").each { |file| fakedataparse(file) - end - } + } + end end diff --git a/spec/integration/ssl/certificate_authority_spec.rb b/spec/integration/ssl/certificate_authority_spec.rb index be82b5fb7..67ff6f215 100755 --- a/spec/integration/ssl/certificate_authority_spec.rb +++ b/spec/integration/ssl/certificate_authority_spec.rb @@ -17,6 +17,7 @@ describe Puppet::SSL::CertificateAuthority do Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir + Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local @ca = Puppet::SSL::CertificateAuthority.new @@ -120,9 +121,7 @@ describe Puppet::SSL::CertificateAuthority do it "should save valid certificates" do @ca.sign("luke.madstop.com") - ssl = %x{which openssl} - - unless ssl + unless ssl = Puppet::Util::which('openssl') pending "No ssl available" else ca_cert = Puppet[:cacert] diff --git a/spec/integration/ssl/certificate_request_spec.rb b/spec/integration/ssl/certificate_request_spec.rb index 365ecce38..8426b9dc5 100755 --- a/spec/integration/ssl/certificate_request_spec.rb +++ b/spec/integration/ssl/certificate_request_spec.rb @@ -21,6 +21,7 @@ describe Puppet::SSL::CertificateRequest do Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir + Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :none diff --git a/spec/integration/ssl/certificate_revocation_list_spec.rb b/spec/integration/ssl/certificate_revocation_list_spec.rb index 127654ce3..44eee363d 100755 --- a/spec/integration/ssl/certificate_revocation_list_spec.rb +++ b/spec/integration/ssl/certificate_revocation_list_spec.rb @@ -17,6 +17,7 @@ describe Puppet::SSL::CertificateRevocationList do Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir + Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local end diff --git a/spec/integration/ssl/host_spec.rb b/spec/integration/ssl/host_spec.rb index 9b4152e83..05862dfc4 100755 --- a/spec/integration/ssl/host_spec.rb +++ b/spec/integration/ssl/host_spec.rb @@ -17,6 +17,7 @@ describe Puppet::SSL::Host do Puppet.settings[:confdir] = @dir Puppet.settings[:vardir] = @dir + Puppet.settings[:group] = Process.gid Puppet::SSL::Host.ca_location = :local diff --git a/spec/integration/util/file_locking_spec.rb b/spec/integration/util/file_locking_spec.rb index 20c61d3d5..50613448b 100755 --- a/spec/integration/util/file_locking_spec.rb +++ b/spec/integration/util/file_locking_spec.rb @@ -5,28 +5,30 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f require 'puppet/util/file_locking' describe Puppet::Util::FileLocking do - it "should be able to keep file corruption from happening when there are multiple writers" do - file = Tempfile.new("puppetspec") - filepath = file.path - file.close!() - file = filepath - data = {:a => :b, :c => "A string", :d => "another string", :e => %w{an array of strings}} - File.open(file, "w") { |f| f.puts YAML.dump(data) } + before :each do + @file = Tempfile.new("puppetspec") + filepath = @file.path + @file.close!() + @file = filepath + @data = {:a => :b, :c => "A string", :d => "another string", :e => %w{an array of strings}} + File.open(@file, "w") { |f| f.puts YAML.dump(@data) } + end + it "should be able to keep file corruption from happening when there are multiple writers threads" do threads = [] sync = Sync.new 9.times { |a| threads << Thread.new { 9.times { |b| sync.synchronize(Sync::SH) { - Puppet::Util::FileLocking.readlock(file) { |f| - YAML.load(f.read).should == data + Puppet::Util::FileLocking.readlock(@file) { |f| + YAML.load(f.read).should == @data } } sleep 0.01 sync.synchronize(Sync::EX) { - Puppet::Util::FileLocking.writelock(file) { |f| - f.puts YAML.dump(data) + Puppet::Util::FileLocking.writelock(@file) { |f| + f.puts YAML.dump(@data) } } } @@ -34,4 +36,22 @@ describe Puppet::Util::FileLocking do } threads.each { |th| th.join } end + + it "should be able to keep file corruption from happening when there are multiple writers processes" do + unless Process.fork + 50.times { |b| + Puppet::Util::FileLocking.writelock(@file) { |f| + f.puts YAML.dump(@data) + } + sleep 0.01 + } + Kernel.exit! + end + + 50.times { |c| + Puppet::Util::FileLocking.readlock(@file) { |f| + YAML.load(f.read).should == @data + } + } + end end diff --git a/spec/lib/puppet_spec/files.rb b/spec/lib/puppet_spec/files.rb index cab4a1e47..52ed903ec 100644 --- a/spec/lib/puppet_spec/files.rb +++ b/spec/lib/puppet_spec/files.rb @@ -1,4 +1,5 @@ require 'fileutils' +require 'tempfile' # A support module for testing files. module PuppetSpec::Files diff --git a/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb b/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb index 15a7cd0ac..3762b7033 100644 --- a/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb +++ b/spec/monkey_patches/add_confine_and_runnable_to_rspec_dsl.rb @@ -5,7 +5,6 @@ dir = File.expand_path(File.dirname(__FILE__)) end require 'spec' -require 'puppettest' require 'puppettest/runnable_test' module Spec diff --git a/spec/monkey_patches/publicize_methods.rb b/spec/monkey_patches/publicize_methods.rb new file mode 100644 index 000000000..b39e9c002 --- /dev/null +++ b/spec/monkey_patches/publicize_methods.rb @@ -0,0 +1,11 @@ +# Some monkey-patching to allow us to test private methods. +class Class + def publicize_methods(*methods) + saved_private_instance_methods = methods.empty? ? self.private_instance_methods : methods + + self.class_eval { public(*saved_private_instance_methods) } + yield + self.class_eval { private(*saved_private_instance_methods) } + end +end + diff --git a/spec/shared_behaviours/file_serving.rb b/spec/shared_behaviours/file_serving.rb index c86453a03..5f5b2b0af 100644 --- a/spec/shared_behaviours/file_serving.rb +++ b/spec/shared_behaviours/file_serving.rb @@ -15,7 +15,7 @@ describe "Puppet::FileServing::Files", :shared => true do @test_class.find(uri) end - it "should use the rest terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is not 'puppet'" do + it "should use the rest terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is not 'puppet' or 'apply'" do uri = "puppet:///fakemod/my/file" Puppet.settings.stubs(:value).returns "foo" Puppet.settings.stubs(:value).with(:name).returns("puppetd") @@ -35,6 +35,17 @@ describe "Puppet::FileServing::Files", :shared => true do @test_class.find(uri) end + it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'apply'" do + uri = "puppet:///fakemod/my/file" + Puppet::Node::Environment.stubs(:new).returns(stub("env", :name => "testing", :module => nil, :modulepath => [])) + Puppet.settings.stubs(:value).returns "" + Puppet.settings.stubs(:value).with(:name).returns("apply") + Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") + @indirection.terminus(:file_server).expects(:find) + @indirection.terminus(:file_server).stubs(:authorized?).returns(true) + @test_class.find(uri) + end + it "should use the file terminus when the 'file' URI scheme is used" do uri = "file:///fakemod/my/file" @indirection.terminus(:file).expects(:find) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 539ae2040..0c4b076f4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,20 +6,11 @@ dir = File.expand_path(File.dirname(__FILE__)) $LOAD_PATH.unshift("#{dir}/") $LOAD_PATH.unshift("#{dir}/lib") # a spec-specific test lib dir $LOAD_PATH.unshift("#{dir}/../lib") -$LOAD_PATH.unshift("#{dir}/../test/lib") # Add the old test dir, so that we can still find our local mocha and spec -# include any gems in vendor/gems -Dir["#{dir}/../vendor/gems/**"].each do |path| - libpath = File.join(path, "lib") - if File.directory?(libpath) - $LOAD_PATH.unshift(libpath) - else - $LOAD_PATH.unshift(path) - end -end +# Don't want puppet getting the command line arguments for rake or autotest +ARGV.clear -require 'puppettest' -require 'puppettest/runnable_test' +require 'puppet' require 'mocha' gem 'rspec', '>=1.2.9' require 'spec/autorun' @@ -29,17 +20,14 @@ module PuppetSpec FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR) end -# load any monkey-patches -Dir["#{dir}/monkey_patches/*.rb"].map { |file| require file } +require 'lib/puppet_spec/files' +require 'monkey_patches/alias_should_to_must' +require 'monkey_patches/add_confine_and_runnable_to_rspec_dsl' +require 'monkey_patches/publicize_methods' Spec::Runner.configure do |config| config.mock_with :mocha -# config.prepend_before :all do -# setup_mocks_for_rspec -# setup if respond_to? :setup -# end -# config.prepend_after :each do Puppet.settings.clear Puppet::Node::Environment.clear @@ -84,14 +72,8 @@ Spec::Runner.configure do |config| Puppet.settings[:bindaddress] = "127.0.0.1" @logs = [] - Puppet::Util::Log.newdestination(@logs) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) end end -# We need this because the RAL uses 'should' as a method. This -# allows us the same behaviour but with a different method name. -class Object - alias :must :should -end - end diff --git a/spec/unit/application/agent_spec.rb b/spec/unit/application/agent_spec.rb index 54726c185..50ef00c57 100755 --- a/spec/unit/application/agent_spec.rb +++ b/spec/unit/application/agent_spec.rb @@ -6,6 +6,7 @@ require 'puppet/agent' require 'puppet/application/agent' require 'puppet/network/server' require 'puppet/daemon' +require 'puppet/network/handler' describe Puppet::Application::Agent do before :each do @@ -13,6 +14,7 @@ describe Puppet::Application::Agent do @puppetd.stubs(:puts) @daemon = stub_everything 'daemon' Puppet::Daemon.stubs(:new).returns(@daemon) + Puppet[:daemonize] = false @agent = stub_everything 'agent' Puppet::Agent.stubs(:new).returns(@agent) @puppetd.preinit @@ -175,13 +177,10 @@ describe Puppet::Application::Agent do @puppetd.options.stubs(:[]) Puppet.stubs(:info) FileTest.stubs(:exists?).returns(true) - Puppet.stubs(:[]) - Puppet.stubs(:[]=) - Puppet.stubs(:[]).with(:libdir).returns("/dev/null/lib") - Puppet.settings.stubs(:print_config?) - Puppet.settings.stubs(:print_config) + Puppet[:libdir] = "/dev/null/lib" Puppet::SSL::Host.stubs(:ca_location=) Puppet::Transaction::Report.stubs(:terminus_class=) + Puppet::Transaction::Report.stubs(:cache_class=) Puppet::Resource::Catalog.stubs(:terminus_class=) Puppet::Resource::Catalog.stubs(:cache_class=) Puppet::Node::Facts.stubs(:terminus_class=) @@ -192,7 +191,7 @@ describe Puppet::Application::Agent do describe "with --test" do before :each do - Puppet.settings.stubs(:handlearg) + #Puppet.settings.stubs(:handlearg) @puppetd.options.stubs(:[]=) end @@ -207,8 +206,9 @@ describe Puppet::Application::Agent do @puppetd.setup_test end it "should set options[:onetime] to true" do - Puppet.expects(:[]=).with(:onetime,true) + Puppet[:onetime] = false @puppetd.setup_test + Puppet[:onetime].should == true end it "should set options[:detailed_exitcodes] to true" do @puppetd.options.expects(:[]=).with(:detailed_exitcodes,true) @@ -264,7 +264,7 @@ describe Puppet::Application::Agent do it "should print puppet config if asked to in Puppet config" do @puppetd.stubs(:exit) - Puppet.settings.stubs(:print_configs?).returns(true) + Puppet[:configprint] = "pluginsync" Puppet.settings.expects(:print_configs) @@ -272,14 +272,14 @@ describe Puppet::Application::Agent do end it "should exit after printing puppet config if asked to in Puppet config" do - Puppet.settings.stubs(:print_configs?).returns(true) + Puppet[:configprint] = "pluginsync" lambda { @puppetd.setup }.should raise_error(SystemExit) end it "should set a central log destination with --centrallogs" do @puppetd.options.stubs(:[]).with(:centrallogs).returns(true) - Puppet.stubs(:[]).with(:server).returns("puppet.reductivelabs.com") + Puppet[:server] = "puppet.reductivelabs.com" Puppet::Util::Log.stubs(:newdestination).with(:syslog) Puppet::Util::Log.expects(:newdestination).with("puppet.reductivelabs.com") @@ -312,9 +312,16 @@ describe Puppet::Application::Agent do @puppetd.setup end + it "should tell the report handler to cache locally as yaml" do + Puppet::Transaction::Report.expects(:cache_class=).with(:yaml) + + @puppetd.setup + end + it "should change the catalog_terminus setting to 'rest'" do - Puppet.expects(:[]=).with(:catalog_terminus, :rest) + Puppet[:catalog_terminus] = :foo @puppetd.setup + Puppet[:catalog_terminus].should == :rest end it "should tell the catalog handler to use cache" do @@ -324,9 +331,10 @@ describe Puppet::Application::Agent do end it "should change the facts_terminus setting to 'facter'" do - Puppet.expects(:[]=).with(:facts_terminus, :facter) + Puppet[:facts_terminus] = :foo @puppetd.setup + Puppet[:facts_terminus].should == :facter end it "should create an agent" do @@ -374,7 +382,7 @@ describe Puppet::Application::Agent do end it "should daemonize if needed" do - Puppet.stubs(:[]).with(:daemonize).returns(true) + Puppet[:daemonize] = true @daemon.expects(:daemonize) @@ -397,7 +405,7 @@ describe Puppet::Application::Agent do end it "should setup listen if told to and not onetime" do - Puppet.stubs(:[]).with(:listen).returns(true) + Puppet[:listen] = true @puppetd.options.stubs(:[]).with(:onetime).returns(false) @puppetd.expects(:setup_listen) @@ -407,7 +415,7 @@ describe Puppet::Application::Agent do describe "when setting up listen" do before :each do - Puppet.stubs(:[]).with(:authconfig).returns('auth') + Puppet[:authconfig] = 'auth' FileTest.stubs(:exists?).with('auth').returns(true) File.stubs(:exist?).returns(true) @puppetd.options.stubs(:[]).with(:serve).returns([]) @@ -419,7 +427,7 @@ describe Puppet::Application::Agent do it "should exit if no authorization file" do Puppet.stubs(:err) - FileTest.stubs(:exists?).with('auth').returns(false) + FileTest.stubs(:exists?).with(Puppet[:authconfig]).returns(false) @puppetd.expects(:exit) @@ -440,9 +448,9 @@ describe Puppet::Application::Agent do end it "should use puppet default port" do - Puppet.stubs(:[]).with(:puppetport).returns(:port) + Puppet[:puppetport] = 32768 - Puppet::Network::Server.expects(:new).with { |args| args[:port] == :port } + Puppet::Network::Server.expects(:new).with { |args| args[:port] == 32768 } @puppetd.setup_listen end @@ -521,7 +529,7 @@ describe Puppet::Application::Agent do end it "should exit with report's computed exit status" do - Puppet.stubs(:[]).with(:noop).returns(false) + Puppet[:noop] = false report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) @puppetd.expects(:exit).with(666) @@ -530,7 +538,7 @@ describe Puppet::Application::Agent do end it "should always exit with 0 if --noop" do - Puppet.stubs(:[]).with(:noop).returns(true) + Puppet[:noop] = true report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) @puppetd.expects(:exit).with(0) diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb index 0b00d1a2e..f07416378 100755 --- a/spec/unit/application/apply_spec.rb +++ b/spec/unit/application/apply_spec.rb @@ -3,6 +3,8 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/apply' +require 'puppet/file_bucket/dipper' +require 'puppet/configurer' describe Puppet::Application::Apply do before :each do @@ -53,9 +55,9 @@ describe Puppet::Application::Apply do Puppet.stubs(:trap) Puppet::Log.stubs(:level=) Puppet.stubs(:parse_config) - require 'lib/puppet/file_bucket/dipper' Puppet::FileBucket::Dipper.stubs(:new) STDIN.stubs(:read) + Puppet::Transaction::Report.stubs(:cache_class=) @apply.options.stubs(:[]).with(any_parameters) end @@ -113,6 +115,11 @@ describe Puppet::Application::Apply do lambda { @apply.setup }.should raise_error(SystemExit) end + it "should tell the report handler to cache locally as yaml" do + Puppet::Transaction::Report.expects(:cache_class=).with(:yaml) + + @apply.setup + end end describe "when executing" do @@ -142,17 +149,16 @@ describe Puppet::Application::Apply do describe "the parseonly command" do before :each do - Puppet.stubs(:[]).with(:environment) + @environment = Puppet::Node::Environment.new("env") + Puppet.stubs(:[]).with(:environment).returns(@environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @apply.stubs(:exit) @apply.options.stubs(:[]).with(:code).returns "some code" - @collection = stub_everything - Puppet::Resource::TypeCollection.stubs(:new).returns(@collection) end - it "should use a Puppet Resource Type Collection to parse the file" do - @collection.expects(:perform_initial_import) + it "should use the environment to parse the file" do + @environment.stubs(:perform_initial_import) @apply.parseonly end @@ -162,7 +168,7 @@ describe Puppet::Application::Apply do end it "should exit with exit code 1 if error" do - @collection.stubs(:perform_initial_import).raises(Puppet::ParseError) + @environment.stubs(:perform_initial_import).raises(Puppet::ParseError) @apply.expects(:exit).with(1) @apply.parseonly end @@ -194,6 +200,9 @@ describe Puppet::Application::Apply do @catalog.stubs(:apply).returns(@transaction) @apply.stubs(:exit) + + Puppet::Util::Storage.stubs(:load) + Puppet::Configurer.any_instance.stubs(:save_last_run_summary) # to prevent it from trying to write files end it "should set the code to run from --code" do @@ -212,7 +221,8 @@ describe Puppet::Application::Apply do @apply.main end - it "should set the manifest if some files are passed on command line" do + it "should set the manifest if a file is passed on command line and the file exists" do + File.stubs(:exist?).with('site.pp').returns true @apply.command_line.stubs(:args).returns(['site.pp']) Puppet.expects(:[]=).with(:manifest,"site.pp") @@ -220,6 +230,23 @@ describe Puppet::Application::Apply do @apply.main end + it "should raise an error if a file is passed on command line and the file does not exist" do + File.stubs(:exist?).with('noexist.pp').returns false + @apply.command_line.stubs(:args).returns(['noexist.pp']) + lambda { @apply.main }.should raise_error(RuntimeError, 'Could not find file noexist.pp') + end + + it "should set the manifest to the first file and warn other files will be skipped" do + File.stubs(:exist?).with('starwarsIV').returns true + File.expects(:exist?).with('starwarsI').never + @apply.command_line.stubs(:args).returns(['starwarsIV', 'starwarsI', 'starwarsII']) + + Puppet.expects(:[]=).with(:manifest,"starwarsIV") + Puppet.expects(:warning).with('Only one file can be applied per run. Skipping starwarsI, starwarsII') + + @apply.main + end + it "should collect the node facts" do Puppet::Node::Facts.expects(:find).returns(@facts) @@ -232,7 +259,7 @@ describe Puppet::Application::Apply do lambda { @apply.main }.should raise_error end - it "should find the node" do + it "should look for the node" do Puppet::Node.expects(:find).returns(@node) @apply.main @@ -284,18 +311,24 @@ describe Puppet::Application::Apply do end it "should call the prerun and postrun commands on a Configurer instance" do - configurer = stub 'configurer' - - Puppet::Configurer.expects(:new).returns configurer - configurer.expects(:execute_prerun_command) - configurer.expects(:execute_postrun_command) + Puppet::Configurer.any_instance.expects(:execute_prerun_command) + Puppet::Configurer.any_instance.expects(:execute_postrun_command) @apply.main end it "should apply the catalog" do - @catalog.expects(:apply) + @catalog.expects(:apply).returns(stub_everything('transaction')) + + @apply.main + end + + it "should save the last run summary" do + Puppet.stubs(:[]).with(:noop).returns(false) + report = stub 'report' + Puppet::Configurer.any_instance.stubs(:initialize_report).returns(report) + Puppet::Configurer.any_instance.expects(:save_last_run_summary).with(report) @apply.main end @@ -303,8 +336,7 @@ describe Puppet::Application::Apply do it "should exit with report's computed exit status" do Puppet.stubs(:[]).with(:noop).returns(false) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) - report = stub 'report', :exit_status => 666 - @transaction.stubs(:report).returns(report) + Puppet::Transaction::Report.any_instance.stubs(:exit_status).returns(666) @apply.expects(:exit).with(666) @apply.main diff --git a/spec/unit/application/cert_spec.rb b/spec/unit/application/cert_spec.rb index b82a2fe89..4663fc938 100755 --- a/spec/unit/application/cert_spec.rb +++ b/spec/unit/application/cert_spec.rb @@ -12,7 +12,7 @@ describe Puppet::Application::Cert do end it "should operate in master run_mode" do - @cert_app.class.run_mode.name.should equal :master + @cert_app.class.run_mode.name.should equal(:master) end it "should ask Puppet::Application to parse Puppet configuration file" do diff --git a/spec/unit/application/doc_spec.rb b/spec/unit/application/doc_spec.rb index 7a22f5b2e..55da5e39a 100755 --- a/spec/unit/application/doc_spec.rb +++ b/spec/unit/application/doc_spec.rb @@ -27,10 +27,6 @@ describe Puppet::Application::Doc do @doc.should respond_to(:rdoc) end - it "should declare a trac command" do - @doc.should respond_to(:trac) - end - it "should declare a fallback for unknown options" do @doc.should respond_to(:handle_unknown) end @@ -270,21 +266,6 @@ describe Puppet::Application::Doc do end describe "when running" do - before :each do - end - - describe "in trac mode" do - it "should call trac for each reference" do - ref = stub 'ref' - Puppet::Util::Reference.stubs(:reference).with(:ref).returns(ref) - @doc.options.stubs(:[]).with(:references).returns([:ref]) - @doc.options.stubs(:[]).with(:mode).returns(:trac) - - ref.expects(:trac) - - @doc.trac - end - end describe "in rdoc mode" do before :each do diff --git a/spec/unit/application/filebucket_spec.rb b/spec/unit/application/filebucket_spec.rb index 6e7a7b819..e6272f179 100644 --- a/spec/unit/application/filebucket_spec.rb +++ b/spec/unit/application/filebucket_spec.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/filebucket' +require 'puppet/file_bucket/dipper' describe Puppet::Application::Filebucket do before :each do diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb index 0baa8229b..e657445a4 100644 --- a/spec/unit/application/master_spec.rb +++ b/spec/unit/application/master_spec.rb @@ -23,7 +23,7 @@ describe Puppet::Application::Master do end it "should operate in master run_mode" do - @master.class.run_mode.name.should equal :master + @master.class.run_mode.name.should equal(:master) end it "should ask Puppet::Application to parse Puppet configuration file" do @@ -257,16 +257,15 @@ describe Puppet::Application::Master do describe "the parseonly command" do before :each do - Puppet.stubs(:[]).with(:environment) + @environment = Puppet::Node::Environment.new("env") + Puppet.stubs(:[]).with(:environment).returns(@environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @master.stubs(:exit) - @collection = stub_everything - Puppet::Resource::TypeCollection.stubs(:new).returns(@collection) end it "should use a Puppet Resource Type Collection to parse the file" do - @collection.expects(:perform_initial_import) + @environment.expects(:perform_initial_import) @master.parseonly end @@ -276,7 +275,7 @@ describe Puppet::Application::Master do end it "should exit with exit code 1 if error" do - @collection.stubs(:perform_initial_import).raises(Puppet::ParseError) + @environment.stubs(:perform_initial_import).raises(Puppet::ParseError) @master.expects(:exit).with(1) @master.parseonly end diff --git a/spec/unit/application/queue_spec.rb b/spec/unit/application/queue_spec.rb index 87c96dfff..bd0d53ab1 100755 --- a/spec/unit/application/queue_spec.rb +++ b/spec/unit/application/queue_spec.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/queue' +require 'puppet/indirector/catalog/queue' describe Puppet::Application::Queue do before :each do diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index 3c354cce9..be7cda340 100755 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -191,35 +191,17 @@ describe Puppet::Application do Puppet.settings.stubs(:optparse_addargs).returns([]) end - it "should create a new option parser when needed" do - option_parser = stub "option parser" - option_parser.stubs(:on) - option_parser.stubs(:default_argv=) - OptionParser.expects(:new).returns(option_parser).once - @app.option_parser.should == option_parser - @app.option_parser.should == option_parser - end - it "should pass the banner to the option parser" do option_parser = stub "option parser" option_parser.stubs(:on) - option_parser.stubs(:default_argv=) + option_parser.stubs(:parse!) @app.class.instance_eval do banner "banner" end OptionParser.expects(:new).with("banner").returns(option_parser) - @app.option_parser - end - - it "should set the optionparser's args to the command line args" do - option_parser = stub "option parser" - option_parser.stubs(:on) - option_parser.expects(:default_argv=).with(%w{ fake args }) - @app.command_line.stubs(:args).returns(%w{ fake args }) - OptionParser.expects(:new).returns(option_parser) - @app.option_parser + @app.parse_options end it "should get options from Puppet.settings.optparse_addargs" do @@ -230,14 +212,14 @@ describe Puppet::Application do it "should add Puppet.settings options to OptionParser" do Puppet.settings.stubs(:optparse_addargs).returns( [["--option","-o", "Funny Option"]]) - - @app.option_parser.expects(:on).with { |*arg| arg == ["--option","-o", "Funny Option"] } - + Puppet.settings.expects(:handlearg).with("--option", 'true') + @app.command_line.stubs(:args).returns(["--option"]) @app.parse_options end it "should ask OptionParser to parse the command-line argument" do - @app.option_parser.expects(:parse!) + @app.command_line.stubs(:args).returns(%w{ fake args }) + OptionParser.any_instance.expects(:parse!).with(%w{ fake args }) @app.parse_options end @@ -268,31 +250,30 @@ describe Puppet::Application do describe "when dealing with an argument not declared directly by the application" do it "should pass it to handle_unknown if this method exists" do - Puppet.settings.stubs(:optparse_addargs).returns([["--not-handled"]]) - @app.option_parser.stubs(:on).yields("value") + Puppet.settings.stubs(:optparse_addargs).returns([["--not-handled", :REQUIRED]]) @app.expects(:handle_unknown).with("--not-handled", "value").returns(true) - + @app.command_line.stubs(:args).returns(["--not-handled", "value"]) @app.parse_options end it "should pass it to Puppet.settings if handle_unknown says so" do - Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet"]]) - @app.option_parser.stubs(:on).yields("value") + Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet", :REQUIRED]]) @app.stubs(:handle_unknown).with("--topuppet", "value").returns(false) Puppet.settings.expects(:handlearg).with("--topuppet", "value") + @app.command_line.stubs(:args).returns(["--topuppet", "value"]) @app.parse_options end it "should pass it to Puppet.settings if there is no handle_unknown method" do - Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet"]]) - @app.option_parser.stubs(:on).yields("value") + Puppet.settings.stubs(:optparse_addargs).returns([["--topuppet", :REQUIRED]]) @app.stubs(:respond_to?).returns(false) Puppet.settings.expects(:handlearg).with("--topuppet", "value") + @app.command_line.stubs(:args).returns(["--topuppet", "value"]) @app.parse_options end @@ -320,7 +301,7 @@ describe Puppet::Application do it "should exit if OptionParser raises an error" do $stderr.stubs(:puts) - @app.option_parser.stubs(:parse!).raises(OptionParser::ParseError.new("blah blah")) + OptionParser.any_instance.stubs(:parse!).raises(OptionParser::ParseError.new("blah blah")) @app.expects(:exit) @@ -488,7 +469,7 @@ describe Puppet::Application do @app.class.option("--[no-]test3","-t") do end - @app.option_parser + @app.parse_options end it "should pass a block that calls our defined method" do @@ -500,7 +481,7 @@ describe Puppet::Application do @app.class.option("--test4","-t") do end - @app.option_parser + @app.parse_options end end @@ -511,7 +492,7 @@ describe Puppet::Application do @app.class.option("--test4","-t") - @app.option_parser + @app.parse_options end it "should give to OptionParser a block that adds the the value to the options array" do @@ -522,7 +503,7 @@ describe Puppet::Application do @app.class.option("--test4","-t") - @app.option_parser + @app.parse_options end end end diff --git a/spec/unit/configurer_spec.rb b/spec/unit/configurer_spec.rb index 0c9d06362..e34e6fffb 100755 --- a/spec/unit/configurer_spec.rb +++ b/spec/unit/configurer_spec.rb @@ -89,9 +89,7 @@ describe Puppet::Configurer, "when executing a catalog run" do @catalog = Puppet::Resource::Catalog.new @catalog.stubs(:apply) @agent.stubs(:retrieve_catalog).returns @catalog - - Puppet::Util::Log.stubs(:newdestination) - Puppet::Util::Log.stubs(:close) + @agent.stubs(:save_last_run_summary) end it "should prepare for the run" do @@ -101,14 +99,14 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should initialize a transaction report if one is not provided" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.run end it "should pass the new report to the catalog" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.stubs(:initialize_report).returns report @catalog.expects(:apply).with{|options| options[:report] == report} @@ -116,7 +114,7 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should use the provided report if it was passed one" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).never @catalog.expects(:apply).with{|options| options[:report] == report} @@ -176,7 +174,7 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should send the report" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.expects(:send_report).with { |r, trans| r == report } @@ -184,7 +182,7 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should send the transaction report with a reference to the transaction if a run was actually made" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report trans = stub 'transaction' @@ -198,7 +196,7 @@ describe Puppet::Configurer, "when executing a catalog run" do it "should send the transaction report even if the catalog could not be retrieved" do @agent.expects(:retrieve_catalog).returns nil - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.expects(:send_report) @@ -208,7 +206,7 @@ describe Puppet::Configurer, "when executing a catalog run" do it "should send the transaction report even if there is a failure" do @agent.expects(:retrieve_catalog).raises "whatever" - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.expects(:send_report) @@ -216,16 +214,16 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should remove the report as a log destination when the run is finished" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report - - Puppet::Util::Log.expects(:close).with(report) + report.expects(:<<).at_least_once @agent.run + Puppet::Util::Log.destinations.should_not include(report) end it "should return the report as the result of the run" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.run.should equal(report) @@ -236,6 +234,7 @@ describe Puppet::Configurer, "when sending a report" do before do Puppet.settings.stubs(:use).returns(true) @configurer = Puppet::Configurer.new + @configurer.stubs(:save_last_run_summary) @report = stub 'report' @trans = stub 'transaction' @@ -284,6 +283,20 @@ describe Puppet::Configurer, "when sending a report" do @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 not save the last run summary if reporting is disabled" do + Puppet.settings[:report] = false + + @configurer.expects(:save_last_run_summary).never + @configurer.send_report(@report) + end + it "should log but not fail if saving the report fails" do Puppet.settings[:report] = true @@ -294,6 +307,36 @@ describe Puppet::Configurer, "when sending a report" do end end +describe Puppet::Configurer, "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 Puppet::Configurer, "when retrieving a catalog" do before do Puppet.settings.stubs(:use).returns(true) @@ -472,23 +515,23 @@ describe Puppet::Configurer, "when preparing for a run" do it "should initialize the metadata store" do @agent.class.stubs(:facts).returns(@facts) @agent.expects(:dostorage) - @agent.prepare + @agent.prepare({}) end it "should download fact plugins" do @agent.expects(:download_fact_plugins) - @agent.prepare + @agent.prepare({}) end it "should download plugins" do @agent.expects(:download_plugins) - @agent.prepare + @agent.prepare({}) end it "should perform the pre-run commands" do @agent.expects(:execute_prerun_command) - @agent.prepare + @agent.prepare({}) end end diff --git a/spec/unit/daemon_spec.rb b/spec/unit/daemon_spec.rb index 15320736c..e24db7881 100755 --- a/spec/unit/daemon_spec.rb +++ b/spec/unit/daemon_spec.rb @@ -1,4 +1,4 @@ -#!/usr/bin/env ruby" +#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/daemon' @@ -142,11 +142,7 @@ describe Puppet::Daemon do describe "when creating its pidfile" do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" - - sync = mock 'sync' - Puppet::Util.expects(:sync).with("me").returns sync - - sync.expects(:synchronize).with(Sync::EX) + Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) @daemon.create_pidfile end @@ -180,10 +176,8 @@ describe Puppet::Daemon do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" - sync = mock 'sync' - Puppet::Util.expects(:sync).with("me").returns sync + Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) - sync.expects(:synchronize).with(Sync::EX) @daemon.remove_pidfile end diff --git a/spec/unit/dsl/resource_type_api_spec.rb b/spec/unit/dsl/resource_type_api_spec.rb index 5abe79ea7..c9a5d272f 100755 --- a/spec/unit/dsl/resource_type_api_spec.rb +++ b/spec/unit/dsl/resource_type_api_spec.rb @@ -4,43 +4,51 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/dsl/resource_type_api' -class DSLAPITester - include Puppet::DSL::ResourceTypeAPI -end - describe Puppet::DSL::ResourceTypeAPI do - before do - @api = DSLAPITester.new + # Verify that the block creates a single AST node through the API, + # instantiate that AST node into a types, and return that type. + def test_api_call(&block) + main_object = Puppet::DSL::ResourceTypeAPI.new + main_object.instance_eval(&block) + created_ast_objects = main_object.instance_eval { @__created_ast_objects__ } + created_ast_objects.length.should == 1 + new_types = created_ast_objects[0].instantiate('') + new_types.length.should == 1 + new_types[0] + ensure + Thread.current[:ruby_file_parse_result] = nil end [:definition, :node, :hostclass].each do |type| method = type == :definition ? "define" : type it "should be able to create a #{type}" do - newtype = Puppet::Resource::Type.new(:hostclass, "foo") - Puppet::Resource::Type.expects(:new).with { |t, n, args| t == type }.returns newtype - @api.send(method, "myname") + newtype = test_api_call { send(method, "myname").should == nil } + newtype.should be_a(Puppet::Resource::Type) + newtype.type.should == type end it "should use the provided name when creating a #{type}" do - type = Puppet::Resource::Type.new(:hostclass, "foo") - Puppet::Resource::Type.expects(:new).with { |t, n, args| n == "myname" }.returns type - @api.send(method, "myname") + newtype = test_api_call { send(method, "myname") } + newtype.name.should == "myname" end unless type == :definition - it "should pass in any provided options" do - type = Puppet::Resource::Type.new(:hostclass, "foo") - Puppet::Resource::Type.expects(:new).with { |t, n, args| args == {:myarg => :myvalue} }.returns type - @api.send(method, "myname", :myarg => :myvalue) + it "should pass in any provided options when creating a #{type}" do + newtype = test_api_call { send(method, "myname", :line => 200) } + newtype.line.should == 200 end end - it "should set any provided block as the type's ruby code" - - it "should add the type to the current environment's known resource types" + it "should set any provided block as the type's ruby code" do + newtype = test_api_call { send(method, "myname") { 'method_result' } } + newtype.ruby_code.call.should == 'method_result' + end end describe "when creating a definition" do - it "should use the provided options to define valid arguments for the resource type" + it "should use the provided options to define valid arguments for the resource type" do + newtype = test_api_call { define("myname", :arg1, :arg2) } + newtype.arguments.should == { 'arg1' => nil, 'arg2' => nil } + end end end diff --git a/spec/unit/indirector/active_record_spec.rb b/spec/unit/indirector/active_record_spec.rb index 258c4e793..40af146c8 100755 --- a/spec/unit/indirector/active_record_spec.rb +++ b/spec/unit/indirector/active_record_spec.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' require 'puppet/indirector/active_record' describe Puppet::Indirector::ActiveRecord do diff --git a/spec/unit/indirector/catalog/compiler_spec.rb b/spec/unit/indirector/catalog/compiler_spec.rb index 2ae5f6ff3..49b8986eb 100755 --- a/spec/unit/indirector/catalog/compiler_spec.rb +++ b/spec/unit/indirector/catalog/compiler_spec.rb @@ -6,9 +6,11 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/indirector/catalog/compiler' +require 'puppet/rails' describe Puppet::Resource::Catalog::Compiler do before do + require 'puppet/rails' Puppet::Rails.stubs(:init) Facter.stubs(:to_hash).returns({}) Facter.stubs(:value).returns(Facter::Util::Fact.new("something")) @@ -33,8 +35,8 @@ describe Puppet::Resource::Catalog::Compiler do Puppet::Node.stubs(:find).with('node1').returns(node1) Puppet::Node.stubs(:find).with('node2').returns(node2) - compiler.find(stub('request', :node => 'node1', :options => {})) - compiler.find(stub('node2request', :node => 'node2', :options => {})) + compiler.find(stub('request', :key => 'node1', :node => 'node1', :options => {})) + compiler.find(stub('node2request', :key => 'node2', :node => 'node2', :options => {})) end it "should provide a method for determining if the catalog is networked" do @@ -70,7 +72,7 @@ describe Puppet::Resource::Catalog::Compiler do @node = Puppet::Node.new @name @node.stubs(:merge) Puppet::Node.stubs(:find).returns @node - @request = stub 'request', :key => "does not matter", :node => @name, :options => {} + @request = stub 'request', :key => @name, :node => @name, :options => {} end it "should directly use provided nodes" do @@ -80,14 +82,14 @@ describe Puppet::Resource::Catalog::Compiler do @compiler.find(@request) end - it "should use the request's node name if no explicit node is provided" do + it "should use the authenticated node name if no request key is provided" do + @request.stubs(:key).returns(nil) Puppet::Node.expects(:find).with(@name).returns(@node) @compiler.expects(:compile).with(@node) @compiler.find(@request) end - it "should use the provided node name if no explicit node is provided and no authenticated node information is available" do - @request.expects(:node).returns nil + it "should use the provided node name by default" do @request.expects(:key).returns "my_node" Puppet::Node.expects(:find).with("my_node").returns @node @@ -155,7 +157,8 @@ describe Puppet::Resource::Catalog::Compiler do @compiler = Puppet::Resource::Catalog::Compiler.new @request = stub 'request', :options => {} - @facts = stub 'facts', :save => nil + @facts = Puppet::Node::Facts.new('hostname', "fact" => "value", "architecture" => "i386") + @facts.stubs(:save).returns(nil) end it "should do nothing if no facts are provided" do @@ -165,12 +168,17 @@ describe Puppet::Resource::Catalog::Compiler do @compiler.extract_facts_from_request(@request) end - it "should use the Facts class to deserialize the provided facts" do + it "should use the Facts class to deserialize the provided facts and update the timestamp" do @request.options[:facts_format] = "foo" @request.options[:facts] = "bar" Puppet::Node::Facts.expects(:convert_from).returns @facts + @facts.timestamp = Time.parse('2010-11-01') + @now = Time.parse('2010-11-02') + Time.expects(:now).returns(@now) + @compiler.extract_facts_from_request(@request) + @facts.timestamp.should == @now end it "should use the provided fact format" do @@ -198,7 +206,7 @@ describe Puppet::Resource::Catalog::Compiler do @compiler = Puppet::Resource::Catalog::Compiler.new @name = "me" @node = mock 'node' - @request = stub 'request', :node => @name, :options => {} + @request = stub 'request', :key => @name, :options => {} @compiler.stubs(:compile) end @@ -217,7 +225,7 @@ describe Puppet::Resource::Catalog::Compiler do @compiler = Puppet::Resource::Catalog::Compiler.new @name = "me" @node = mock 'node' - @request = stub 'request', :node => @name, :options => {} + @request = stub 'request', :key => @name, :options => {} @compiler.stubs(:compile) Puppet::Node.stubs(:find).with(@name).returns(@node) end diff --git a/spec/unit/indirector/facts/active_record_spec.rb b/spec/unit/indirector/facts/active_record_spec.rb index 0cdb70e01..0bdcfcb77 100755 --- a/spec/unit/indirector/facts/active_record_spec.rb +++ b/spec/unit/indirector/facts/active_record_spec.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../../spec_helper' +require 'puppet/rails' require 'puppet/node/facts' describe "Puppet::Node::Facts::ActiveRecord" do diff --git a/spec/unit/indirector/facts/yaml_spec.rb b/spec/unit/indirector/facts/yaml_spec.rb index e7bac3471..37a1bcae0 100755 --- a/spec/unit/indirector/facts/yaml_spec.rb +++ b/spec/unit/indirector/facts/yaml_spec.rb @@ -10,9 +10,9 @@ describe Puppet::Node::Facts::Yaml do Puppet::Node::Facts::Yaml.superclass.should equal(Puppet::Indirector::Yaml) end - it "should have documentation" do Puppet::Node::Facts::Yaml.doc.should_not be_nil + Puppet::Node::Facts::Yaml.doc.should_not be_empty end it "should be registered with the facts indirection" do @@ -20,7 +20,7 @@ describe Puppet::Node::Facts::Yaml do Puppet::Node::Facts::Yaml.indirection.should equal(indirection) end - it "should have its name set to :facts" do + it "should have its name set to :yaml" do Puppet::Node::Facts::Yaml.name.should == :yaml end end diff --git a/spec/unit/indirector/inventory/yaml_spec.rb b/spec/unit/indirector/inventory/yaml_spec.rb new file mode 100644 index 000000000..9f0c54353 --- /dev/null +++ b/spec/unit/indirector/inventory/yaml_spec.rb @@ -0,0 +1,221 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/node/inventory' +require 'puppet/indirector/inventory/yaml' +require 'puppet/indirector/request' + +describe Puppet::Node::Inventory::Yaml do + def assert_search_matches(matching, nonmatching, query) + request = Puppet::Indirector::Request.new(:inventory, :search, nil, query) + + Dir.stubs(:glob).returns(matching.keys + nonmatching.keys) + [matching, nonmatching].each do |examples| + examples.each do |key, value| + YAML.stubs(:load_file).with(key).returns value + end + end + Puppet::Node::Inventory::Yaml.new.search(request).should =~ matching.values.map {|facts| facts.name} + end + + it "should return node names that match the search query options" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '4'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "i386", 'processor_count' => '4', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), + "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), + }, + {'facts.architecture' => 'i386', 'facts.processor_count' => '4'} + ) + end + + it "should return empty array when no nodes match the search query options" do + assert_search_matches({}, { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '10'), + "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), + }, + {'facts.processor_count.lt' => '4', 'facts.processor_count.gt' => '4'} + ) + end + + + it "should return node names that match the search query options with the greater than operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '10', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '3'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.gt' => '4'} + ) + end + + it "should return node names that match the search query options with the less than operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '30', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '50' ), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '100'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.lt' => '50'} + ) + end + + it "should return node names that match the search query options with the less than or equal to operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '100' ), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5000'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.le' => '50'} + ) + end + + it "should return node names that match the search query options with the greater than or equal to operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '100'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '40'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.ge' => '50'} + ) + end + + it "should return node names that match the search query options with the not equal operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => 'arm' ), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => 'powerpc', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "i386" ), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.architecture.ne' => 'i386'} + ) + end + + def apply_timestamp(facts, timestamp) + facts.timestamp = timestamp + facts + end + + it "should be able to query based on meta.timestamp.gt" do + assert_search_matches({ + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + }, + { + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + {'meta.timestamp.gt' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.le" do + assert_search_matches({ + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + }, + {'meta.timestamp.le' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.lt" do + assert_search_matches({ + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + {'meta.timestamp.lt' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.ge" do + assert_search_matches({ + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + {'meta.timestamp.ge' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.eq" do + assert_search_matches({ + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + {'meta.timestamp.eq' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp" do + assert_search_matches({ + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + {'meta.timestamp' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.ne" do + assert_search_matches({ + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + { + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + {'meta.timestamp.ne' => '2010-10-15'} + ) + end +end diff --git a/spec/unit/indirector/node/active_record_spec.rb b/spec/unit/indirector/node/active_record_spec.rb index 6cc3f5132..3540ef738 100755 --- a/spec/unit/indirector/node/active_record_spec.rb +++ b/spec/unit/indirector/node/active_record_spec.rb @@ -3,7 +3,6 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/node' -require 'spec/lib/puppet_spec/files.rb' describe "Puppet::Node::ActiveRecord" do include PuppetSpec::Files diff --git a/spec/unit/indirector/node/ldap_spec.rb b/spec/unit/indirector/node/ldap_spec.rb index f9c5efa07..042e7bd54 100755 --- a/spec/unit/indirector/node/ldap_spec.rb +++ b/spec/unit/indirector/node/ldap_spec.rb @@ -5,10 +5,6 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/indirector/node/ldap' describe Puppet::Node::Ldap do - before do - Puppet::Node::Facts.stubs(:terminus_class).returns :yaml - end - describe "when searching for a single node" do before :each do @searcher = Puppet::Node::Ldap.new @@ -23,17 +19,17 @@ describe Puppet::Node::Ldap do end it "should convert the hostname into a search filter" do - entry = stub 'entry', :dn => 'cn=mynode.domain.com,ou=hosts,dc=madstop,dc=com', :vals => %w{}, :to_hash => {"environment" => 'production'} + entry = stub 'entry', :dn => 'cn=mynode.domain.com,ou=hosts,dc=madstop,dc=com', :vals => %w{}, :to_hash => {} @searcher.expects(:ldapsearch).with("(&(objectclass=puppetClient)(cn=#{@name}))").yields entry - @searcher.name2hash(@name, 'production', 'parent') + @searcher.name2hash(@name) end it "should convert any found entry into a hash" do - entry = stub 'entry', :dn => 'cn=mynode.domain.com,ou=hosts,dc=madstop,dc=com', :vals => %w{}, :to_hash => {"environment" => 'production'} + entry = stub 'entry', :dn => 'cn=mynode.domain.com,ou=hosts,dc=madstop,dc=com', :vals => %w{}, :to_hash => {} @searcher.expects(:ldapsearch).with("(&(objectclass=puppetClient)(cn=#{@name}))").yields entry - myhash = {"myhash" => true, :environment => 'production'} + myhash = {"myhash" => true} @searcher.expects(:entry2hash).with(entry).returns myhash - @searcher.name2hash(@name, 'production', 'parent').should == myhash + @searcher.name2hash(@name).should == myhash end # This heavily tests our entry2hash method, so we don't have to stub out the stupid entry information any more. @@ -128,20 +124,20 @@ describe Puppet::Node::Ldap do end it "should search first for the provided key" do - @searcher.expects(:name2hash).with("mynode.domain.com", 'production', 'child').returns({}) + @searcher.expects(:name2hash).with("mynode.domain.com").returns({}) @searcher.find(@request) end it "should search for the short version of the provided key if the key looks like a hostname and no results are found for the key itself" do - @searcher.expects(:name2hash).with("mynode.domain.com", 'production', 'child').returns(nil) - @searcher.expects(:name2hash).with("mynode", 'production', 'child').returns({}) + @searcher.expects(:name2hash).with("mynode.domain.com").returns(nil) + @searcher.expects(:name2hash).with("mynode").returns({}) @searcher.find(@request) end it "should search for default information if no information can be found for the key" do - @searcher.expects(:name2hash).with("mynode.domain.com", 'production', 'child').returns(nil) - @searcher.expects(:name2hash).with("mynode", 'production', 'child').returns(nil) - @searcher.expects(:name2hash).with("default", 'production', 'child').returns({}) + @searcher.expects(:name2hash).with("mynode.domain.com").returns(nil) + @searcher.expects(:name2hash).with("mynode").returns(nil) + @searcher.expects(:name2hash).with("default").returns({}) @searcher.find(@request) end @@ -162,8 +158,8 @@ describe Puppet::Node::Ldap do end it "should create the node with the correct name, even if it was found by a different name" do - @searcher.expects(:name2hash).with("mynode.domain.com", 'production', 'child').returns nil - @searcher.expects(:name2hash).with("mynode", 'production', 'child').returns @result + @searcher.expects(:name2hash).with("mynode.domain.com").returns nil + @searcher.expects(:name2hash).with("mynode").returns @result Puppet::Node.expects(:new).with("mynode.domain.com").returns @node @searcher.find(@request) @@ -213,15 +209,17 @@ describe Puppet::Node::Ldap do @parent = {:classes => [], :parameters => {}} @parent_parent = {:classes => [], :parameters => {}} - @searcher.stubs(:name2hash).with{|name, env, mode| name == @name}.returns(@entry) - @searcher.stubs(:name2hash).with{|name, env, mode| name == 'parent'}.returns(@parent) - @searcher.stubs(:name2hash).with{|name, env, mode| name == 'parent_parent'}.returns(@parent_parent) + @searcher.stubs(:name2hash).with(@name).returns(@entry) + @searcher.stubs(:name2hash).with('parent').returns(@parent) + @searcher.stubs(:name2hash).with('parent_parent').returns(@parent_parent) @searcher.stubs(:parent_attribute).returns(:parent) end it "should search for the parent node" do @entry[:parent] = "parent" + @searcher.expects(:name2hash).with(@name).returns @entry + @searcher.expects(:name2hash).with('parent').returns @parent @searcher.find(@request) end @@ -229,7 +227,7 @@ describe Puppet::Node::Ldap do it "should fail if the parent cannot be found" do @entry[:parent] = "parent" - @searcher.expects(:name2hash).with('parent', 'production', 'parent').returns nil + @searcher.expects(:name2hash).with('parent').returns nil proc { @searcher.find(@request) }.should raise_error(Puppet::Error) end diff --git a/spec/unit/indirector/report/yaml_spec.rb b/spec/unit/indirector/report/yaml_spec.rb new file mode 100644 index 000000000..610c9ae43 --- /dev/null +++ b/spec/unit/indirector/report/yaml_spec.rb @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/transaction/report' +require 'puppet/indirector/report/yaml' + +describe Puppet::Transaction::Report::Yaml do + it "should be a subclass of the Yaml terminus" do + Puppet::Transaction::Report::Yaml.superclass.should equal(Puppet::Indirector::Yaml) + end + + it "should have documentation" do + Puppet::Transaction::Report::Yaml.doc.should_not be_nil + end + + it "should be registered with the report indirection" do + indirection = Puppet::Indirector::Indirection.instance(:report) + Puppet::Transaction::Report::Yaml.indirection.should equal(indirection) + end + + it "should have its name set to :yaml" do + Puppet::Transaction::Report::Yaml.name.should == :yaml + end + + it "should inconditionnally save/load from the --lastrunreport setting" do + indirection = stub 'indirection', :name => :my_yaml, :register_terminus_type => nil + Puppet::Indirector::Indirection.stubs(:instance).with(:my_yaml).returns(indirection) + store_class = Class.new(Puppet::Transaction::Report::Yaml) do + def self.to_s + "MyYaml::MyType" + end + end + store = store_class.new + + store.path(:me).should == Puppet[:lastrunreport] + end +end diff --git a/spec/unit/indirector/yaml_spec.rb b/spec/unit/indirector/yaml_spec.rb index 134d476ba..86c13c5a0 100755 --- a/spec/unit/indirector/yaml_spec.rb +++ b/spec/unit/indirector/yaml_spec.rb @@ -40,6 +40,18 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do @store.path(:me).should =~ %r{^/client/yaml/dir} end + it "should use the extension if one is specified" do + Puppet.run_mode.expects(:master?).returns true + Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" + @store.path(:me,'.farfignewton').should =~ %r{\.farfignewton$} + end + + it "should assume an extension of .yaml if none is specified" do + Puppet.run_mode.expects(:master?).returns true + Puppet.settings.expects(:value).with(:yamldir).returns "/server/yaml/dir" + @store.path(:me).should =~ %r{\.yaml$} + end + it "should store all files in a single file root set in the Puppet defaults" do @store.path(:me).should =~ %r{^#{@dir}} end @@ -120,8 +132,8 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do @request = stub 'request', :key => "*", :instance => @subject @one = mock 'one' @two = mock 'two' - @store.expects(:base).returns "/my/yaml/dir" - Dir.expects(:glob).with(File.join("/my/yaml/dir", @store.class.indirection_name.to_s, @request.key)).returns(%w{one.yaml two.yaml}) + @store.expects(:path).with(@request.key,'').returns :glob + Dir.expects(:glob).with(:glob).returns(%w{one.yaml two.yaml}) YAML.expects(:load_file).with("one.yaml").returns @one; YAML.expects(:load_file).with("two.yaml").returns @two; @store.search(@request).should == [@one, @two] @@ -130,16 +142,16 @@ describe Puppet::Indirector::Yaml, " when choosing file location" do it "should return an array containing a single instance of fact when globbing 'one*'" do @request = stub 'request', :key => "one*", :instance => @subject @one = mock 'one' - @store.expects(:base).returns "/my/yaml/dir" - Dir.expects(:glob).with(File.join("/my/yaml/dir", @store.class.indirection_name.to_s, @request.key)).returns(%w{one.yaml}) + @store.expects(:path).with(@request.key,'').returns :glob + Dir.expects(:glob).with(:glob).returns(%w{one.yaml}) YAML.expects(:load_file).with("one.yaml").returns @one; @store.search(@request).should == [@one] end it "should return an empty array when the glob doesn't match anything" do @request = stub 'request', :key => "f*ilglobcanfail*", :instance => @subject - @store.expects(:base).returns "/my/yaml/dir" - Dir.expects(:glob).with(File.join("/my/yaml/dir", @store.class.indirection_name.to_s, @request.key)).returns([]) + @store.expects(:path).with(@request.key,'').returns :glob + Dir.expects(:glob).with(:glob).returns [] @store.search(@request).should == [] end end diff --git a/spec/unit/network/handler/fileserver_spec.rb b/spec/unit/network/handler/fileserver_spec.rb index 40d1e57cd..b37d4f551 100644 --- a/spec/unit/network/handler/fileserver_spec.rb +++ b/spec/unit/network/handler/fileserver_spec.rb @@ -4,9 +4,8 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet/network/handler/fileserver' - describe Puppet::Network::Handler::FileServer do - require 'tmpdir' + include PuppetSpec::Files def create_file(filename) File.open(filename, "w") { |f| f.puts filename} @@ -20,8 +19,7 @@ describe Puppet::Network::Handler::FileServer do end before do - @basedir = File.join(Dir.tmpdir, "test_network_handler") - Dir.mkdir(@basedir) + @basedir = tmpdir("test_network_handler") @file = File.join(@basedir, "aFile") @link = File.join(@basedir, "aLink") create_file(@file) diff --git a/spec/unit/network/http/api/v1_spec.rb b/spec/unit/network/http/api/v1_spec.rb index c593242c0..84b98ddaf 100644 --- a/spec/unit/network/http/api/v1_spec.rb +++ b/spec/unit/network/http/api/v1_spec.rb @@ -32,7 +32,7 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the first field of the URI as the environment" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).environment.should == Puppet::Node::Environment.new("env") + @tester.uri2indirection("GET", "/env/foo/bar", {})[3][:environment].should == "env" end it "should fail if the environment is not alphanumeric" do @@ -40,11 +40,11 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the environment from the URI even if one is specified in the parameters" do - @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"}).environment.should == Puppet::Node::Environment.new("env") + @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"})[3][:environment].should == "env" end it "should use the second field of the URI as the indirection name" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).indirection_name.should == :foo + @tester.uri2indirection("GET", "/env/foo/bar", {})[0].should == "foo" end it "should fail if the indirection name is not alphanumeric" do @@ -52,11 +52,11 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the remainder of the URI as the indirection key" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).key.should == "bar" + @tester.uri2indirection("GET", "/env/foo/bar", {})[2].should == "bar" end it "should support the indirection key being a /-separated file path" do - @tester.uri2indirection("GET", "/env/foo/bee/baz/bomb", {}).key.should == "bee/baz/bomb" + @tester.uri2indirection("GET", "/env/foo/bee/baz/bomb", {})[2].should == "bee/baz/bomb" end it "should fail if no indirection key is specified" do @@ -65,19 +65,31 @@ describe Puppet::Network::HTTP::API::V1 do end it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is singular" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).method.should == :find + @tester.uri2indirection("GET", "/env/foo/bar", {})[1].should == :find end it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is plural" do - @tester.uri2indirection("GET", "/env/foos/bar", {}).method.should == :search + @tester.uri2indirection("GET", "/env/foos/bar", {})[1].should == :search + end + + it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is facts" do + @tester.uri2indirection("GET", "/env/facts/bar", {})[1].should == :find + end + + it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is facts" do + @tester.uri2indirection("PUT", "/env/facts/bar", {})[1].should == :save + end + + it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is inventory" do + @tester.uri2indirection("GET", "/env/inventory/search", {})[1].should == :search end it "should choose 'delete' as the indirection method if the http method is a DELETE and the indirection name is singular" do - @tester.uri2indirection("DELETE", "/env/foo/bar", {}).method.should == :destroy + @tester.uri2indirection("DELETE", "/env/foo/bar", {})[1].should == :destroy end it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is singular" do - @tester.uri2indirection("PUT", "/env/foo/bar", {}).method.should == :save + @tester.uri2indirection("PUT", "/env/foo/bar", {})[1].should == :save end it "should fail if an indirection method cannot be picked" do @@ -86,7 +98,8 @@ describe Puppet::Network::HTTP::API::V1 do it "should URI unescape the indirection key" do escaped = URI.escape("foo bar") - @tester.uri2indirection("GET", "/env/foo/#{escaped}", {}).key.should == "foo bar" + indirection_name, method, key, params = @tester.uri2indirection("GET", "/env/foo/#{escaped}", {}) + key.should == "foo bar" end end diff --git a/spec/unit/network/http/handler_spec.rb b/spec/unit/network/http/handler_spec.rb index 76a9c5530..16f1b5349 100755 --- a/spec/unit/network/http/handler_spec.rb +++ b/spec/unit/network/http/handler_spec.rb @@ -79,37 +79,22 @@ describe Puppet::Network::HTTP::Handler do @handler.process(@request, @response) end - it "should call the 'do' method associated with the indirection method" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request + it "should call the 'do' method and delegate authorization to the RestAuthorization layer" do + @handler.expects(:uri2indirection).returns(["facts", :mymethod, "key", {:node => "name"}]) - request.expects(:method).returns "mymethod" + @handler.expects(:do_mymethod).with("facts", "key", {:node => "name"}, @request, @response) - @handler.expects(:do_mymethod).with(request, @request, @response) - - @handler.process(@request, @response) - end - - it "should delegate authorization to the RestAuthorization layer" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request - - request.expects(:method).returns "mymethod" - - @handler.expects(:do_mymethod).with(request, @request, @response) - - @handler.expects(:check_authorization).with(request) + @handler.expects(:check_authorization).with("facts", :mymethod, "key", {:node => "name"}) @handler.process(@request, @response) end it "should return 403 if the request is not authorized" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request + @handler.expects(:uri2indirection).returns(["facts", :mymethod, "key", {:node => "name"}]) @handler.expects(:do_mymethod).never - @handler.expects(:check_authorization).with(request).raises(Puppet::Network::AuthorizationError.new("forbindden")) + @handler.expects(:check_authorization).with("facts", :mymethod, "key", {:node => "name"}).raises(Puppet::Network::AuthorizationError.new("forbidden")) @handler.expects(:set_response).with { |response, body, status| status == 403 } @@ -117,7 +102,7 @@ describe Puppet::Network::HTTP::Handler do end it "should serialize a controller exception when an exception is thrown while finding the model instance" do - @handler.expects(:uri2indirection).returns stub("request", :method => :find) + @handler.expects(:uri2indirection).returns(["facts", :find, "key", {:node => "name"}]) @handler.expects(:do_find).raises(ArgumentError, "The exception") @handler.expects(:set_response).with { |response, body, status| body == "The exception" and status == 400 } @@ -141,9 +126,8 @@ describe Puppet::Network::HTTP::Handler do describe "when finding a model instance" do before do - @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "my_result", :model => @model_class - @model_class.stubs(:find).returns @result + Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" Puppet::Network::FormatHandler.stubs(:format).returns @format @@ -153,40 +137,37 @@ describe Puppet::Network::HTTP::Handler do end it "should use the indirection request to find the model class" do - @irequest.expects(:model).returns @model_class - - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use the escaped request key" do @model_class.expects(:find).with do |key, args| key == "my_result" end.returns @result - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) @model_class.expects(:find).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end.returns @result - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should set the content type to the first format specified in the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @handler.expects(:set_content_type).with(@response, @oneformat) - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should fail if no accept header is provided" do @handler.expects(:accept_header).with(@request).returns nil - lambda { @handler.do_find(@irequest, @request, @response) }.should raise_error(ArgumentError) + lambda { @handler.do_find("my_handler", "my_result", {}, @request, @response) }.should raise_error(ArgumentError) end it "should fail if the accept header does not contain a valid format" do @handler.expects(:accept_header).with(@request).returns "" - lambda { @handler.do_find(@irequest, @request, @response) }.should raise_error(RuntimeError) + lambda { @handler.do_find("my_handler", "my_result", {}, @request, @response) }.should raise_error(RuntimeError) end it "should not use an unsuitable format" do @@ -198,7 +179,7 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:set_content_type).with(@response, bar) # the suitable one - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should render the result using the first format specified in the accept header" do @@ -206,12 +187,12 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:accept_header).with(@request).returns "one,two" @result.expects(:render).with(@oneformat) - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use the default status when a model find call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should return a serialized object when a model find call succeeds" do @@ -220,14 +201,14 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:set_response).with { |response, body, status| body == "my_rendered_object" } @model_class.stubs(:find).returns(@model_instance) - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should return a 404 when no model instance can be found" do @model_class.stubs(:name).returns "my name" @handler.expects(:set_response).with { |response, body, status| status == 404 } @model_class.stubs(:find).returns(nil) - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should write a log message when no model instance can be found" do @@ -236,7 +217,7 @@ describe Puppet::Network::HTTP::Handler do Puppet.expects(:info).with("Could not find my_handler for 'my_result'") - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end @@ -246,13 +227,13 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:format_to_use).returns(@oneformat) @model_instance.expects(:render).with(@oneformat).returns "my_rendered_object" @model_class.stubs(:find).returns(@model_instance) - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end end describe "when searching for model instances" do before do - @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @result1 = mock 'result1' @result2 = mock 'results' @@ -269,29 +250,26 @@ describe Puppet::Network::HTTP::Handler do end it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class - - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) @model_class.expects(:search).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end.returns @result - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should use the default status when a model search call succeeds" do @model_class.stubs(:search).returns(@result) - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should set the content type to the first format returned by the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @handler.expects(:set_content_type).with(@response, @oneformat) - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should return a list of serialized objects when a model search call succeeds" do @@ -302,57 +280,56 @@ describe Puppet::Network::HTTP::Handler do @model_class.expects(:render_multiple).with(@oneformat, @result).returns "my rendered instances" @handler.expects(:set_response).with { |response, data| data == "my rendered instances" } - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end - it "should return a 404 when searching returns an empty array" do - @model_class.stubs(:name).returns "my name" - @handler.expects(:set_response).with { |response, body, status| status == 404 } + it "should return [] when searching returns an empty array" do + @handler.expects(:accept_header).with(@request).returns "one,two" @model_class.stubs(:search).returns([]) - @handler.do_search(@irequest, @request, @response) + @model_class.expects(:render_multiple).with(@oneformat, []).returns "[]" + + + @handler.expects(:set_response).with { |response, data| data == "[]" } + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should return a 404 when searching returns nil" do @model_class.stubs(:name).returns "my name" @handler.expects(:set_response).with { |response, body, status| status == 404 } - @model_class.stubs(:search).returns([]) - @handler.do_search(@irequest, @request, @response) + @model_class.stubs(:search).returns(nil) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end end describe "when destroying a model instance" do before do - @irequest = stub 'indirection_request', :method => :destroy, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @result = stub 'result', :render => "the result" @model_class.stubs(:destroy).returns @result end it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class - - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end it "should use the escaped request key to destroy the instance in the model" do - @irequest.expects(:key).returns "foo bar" @model_class.expects(:destroy).with do |key, args| key == "foo bar" end - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "foo bar", {}, @request, @response) end it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) @model_class.expects(:destroy).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should use the default status code a model destroy call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end it "should return a yaml-encoded result when a model destroy call succeeds" do @@ -361,13 +338,13 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:set_response).with { |response, body, status| body == "the result" } - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end end describe "when saving a model instance" do before do - @irequest = stub 'indirection_request', :method => :save, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + Puppet::Indirector::Indirection.stubs(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @handler.stubs(:body).returns('my stuff') @handler.stubs(:content_type_header).returns("text/yaml") @@ -383,43 +360,41 @@ describe Puppet::Network::HTTP::Handler do end it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class - - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should use the 'body' hook to retrieve the body of the request" do @handler.expects(:body).returns "my body" @model_class.expects(:convert_from).with { |format, body| body == "my body" }.returns @model_instance - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should fail to save model if data is not specified" do @handler.stubs(:body).returns('') - lambda { @handler.do_save(@irequest, @request, @response) }.should raise_error(ArgumentError) + lambda { @handler.do_save("my_handler", "my_result", {}, @request, @response) }.should raise_error(ArgumentError) end it "should use a common method for determining the request parameters" do @model_instance.expects(:save).with('key').once - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "key", {}, @request, @response) end it "should use the default status when a model save call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should return the yaml-serialized result when a model save call succeeds" do @model_instance.stubs(:save).returns(@model_instance) @model_instance.expects(:to_yaml).returns('foo') - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should set the content to yaml" do @handler.expects(:set_content_type).with(@response, @yamlformat) - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should use the content-type header to know the body format" do @@ -428,7 +403,7 @@ describe Puppet::Network::HTTP::Handler do @model_class.expects(:convert_from).with { |format, body| format == "format" }.returns @model_instance - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end end end diff --git a/spec/unit/network/http/rack/rest_spec.rb b/spec/unit/network/http/rack/rest_spec.rb index 9b3e1e59f..96cf84c37 100755 --- a/spec/unit/network/http/rack/rest_spec.rb +++ b/spec/unit/network/http/rack/rest_spec.rb @@ -82,8 +82,8 @@ describe "Puppet::Network::HTTP::RackREST" do @file.stubs(:is_a?).with(File).returns(true) end - it "should set the Content-Length header" do - @response.expects(:[]=).with("Content-Length", 100) + it "should set the Content-Length header as a string" do + @response.expects(:[]=).with("Content-Length", '100') @handler.set_response(@response, @file, 200) end @@ -246,4 +246,4 @@ describe Puppet::Network::HTTP::RackREST::RackFile do @file.expects(:close) @rackfile.close end -end
\ No newline at end of file +end diff --git a/spec/unit/network/http/rack/xmlrpc_spec.rb b/spec/unit/network/http/rack/xmlrpc_spec.rb index 63ba28bf2..870438f2c 100755 --- a/spec/unit/network/http/rack/xmlrpc_spec.rb +++ b/spec/unit/network/http/rack/xmlrpc_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'puppet/network/handler' require 'puppet/network/http/rack' if Puppet.features.rack? require 'puppet/network/http/rack/xmlrpc' if Puppet.features.rack? diff --git a/spec/unit/network/http/rack_spec.rb b/spec/unit/network/http/rack_spec.rb index df42a1ffa..8be9ccb50 100755 --- a/spec/unit/network/http/rack_spec.rb +++ b/spec/unit/network/http/rack_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../spec_helper' +require 'puppet/network/handler' require 'puppet/network/http/rack' if Puppet.features.rack? describe "Puppet::Network::HTTP::Rack" do diff --git a/spec/unit/network/http/webrick/rest_spec.rb b/spec/unit/network/http/webrick/rest_spec.rb index aa2b93176..b00c62dc4 100755 --- a/spec/unit/network/http/webrick/rest_spec.rb +++ b/spec/unit/network/http/webrick/rest_spec.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../../../spec_helper' require 'puppet/network/http' +require 'webrick' require 'puppet/network/http/webrick/rest' describe Puppet::Network::HTTP::WEBrickREST do diff --git a/spec/unit/network/http/webrick_spec.rb b/spec/unit/network/http/webrick_spec.rb index 2a6ef2268..8e7c92b71 100755 --- a/spec/unit/network/http/webrick_spec.rb +++ b/spec/unit/network/http/webrick_spec.rb @@ -4,6 +4,7 @@ # Copyright (c) 2007. All rights reserved. require File.dirname(__FILE__) + '/../../../spec_helper' +require 'puppet/network/handler' require 'puppet/network/http' require 'puppet/network/http/webrick' diff --git a/spec/unit/network/rest_authconfig_spec.rb b/spec/unit/network/rest_authconfig_spec.rb index 351f3f040..e81eb41ed 100755 --- a/spec/unit/network/rest_authconfig_spec.rb +++ b/spec/unit/network/rest_authconfig_spec.rb @@ -30,9 +30,6 @@ describe Puppet::Network::RestAuthConfig do @acl = stub_everything 'rights' @authconfig.rights = @acl - - @request = stub 'request', :indirection_name => "path", :key => "to/resource", :ip => "127.0.0.1", - :node => "me", :method => :save, :environment => :env, :authenticated => true end it "should use the puppet default rest authorization file" do @@ -41,16 +38,10 @@ describe Puppet::Network::RestAuthConfig do Puppet::Network::RestAuthConfig.new(nil, false) end - it "should read the config file when needed" do - @authconfig.expects(:read) - - @authconfig.allowed?(@request) - end - it "should ask for authorization to the ACL subsystem" do @acl.expects(:fail_on_deny).with("/path/to/resource", :node => "me", :ip => "127.0.0.1", :method => :save, :environment => :env, :authenticated => true) - @authconfig.allowed?(@request) + @authconfig.allowed?("path", :save, "to/resource", :ip => "127.0.0.1", :node => "me", :environment => :env, :authenticated => true) end describe "when defining an acl with mk_acl" do diff --git a/spec/unit/network/rest_authorization_spec.rb b/spec/unit/network/rest_authorization_spec.rb deleted file mode 100755 index 0cb0bcee9..000000000 --- a/spec/unit/network/rest_authorization_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../../spec_helper' - -require 'puppet/network/rest_authorization' - -class RestAuthorized - include Puppet::Network::RestAuthorization -end - - -describe Puppet::Network::RestAuthorization do - before :each do - @auth = RestAuthorized.new - @authconig = stub 'authconfig' - @auth.stubs(:authconfig).returns(@authconfig) - - @request = stub_everything 'request' - @request.stubs(:method).returns(:find) - @request.stubs(:node).returns("node") - @request.stubs(:ip).returns("ip") - end - - describe "when testing request authorization" do - it "should delegate to the current rest authconfig" do - @authconfig.expects(:allowed?).with(@request).returns(true) - - @auth.check_authorization(@request) - end - - it "should raise an AuthorizationError if authconfig raises an AuthorizationError" do - @authconfig.expects(:allowed?).with(@request).raises(Puppet::Network::AuthorizationError.new("forbidden")) - - lambda { @auth.check_authorization(@request) }.should raise_error(Puppet::Network::AuthorizationError) - end - - it "should not raise an AuthorizationError if request is allowed" do - @authconfig.expects(:allowed?).with(@request).returns(true) - - lambda { @auth.check_authorization(@request) }.should_not raise_error(Puppet::Network::AuthorizationError) - end - end -end diff --git a/spec/unit/network/server_spec.rb b/spec/unit/network/server_spec.rb index ccd9c082e..c2496dcca 100755 --- a/spec/unit/network/server_spec.rb +++ b/spec/unit/network/server_spec.rb @@ -5,6 +5,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/network/server' +require 'puppet/network/handler' describe Puppet::Network::Server do before do @@ -161,11 +162,7 @@ describe Puppet::Network::Server do describe "when creating its pidfile" do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" - - sync = mock 'sync' - Puppet::Util.expects(:sync).with("me").returns sync - - sync.expects(:synchronize).with(Sync::EX) + Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) @server.create_pidfile end @@ -198,11 +195,7 @@ describe Puppet::Network::Server do describe "when removing its pidfile" do it "should use an exclusive mutex" do Puppet.settings.expects(:value).with(:name).returns "me" - - sync = mock 'sync' - Puppet::Util.expects(:sync).with("me").returns sync - - sync.expects(:synchronize).with(Sync::EX) + Puppet::Util.expects(:synchronize_on).with("me",Sync::EX) @server.remove_pidfile end diff --git a/spec/unit/network/xmlrpc/client_spec.rb b/spec/unit/network/xmlrpc/client_spec.rb index 0b9b2b095..8440d39fa 100755 --- a/spec/unit/network/xmlrpc/client_spec.rb +++ b/spec/unit/network/xmlrpc/client_spec.rb @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +require 'puppet/network/client' Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } diff --git a/spec/unit/node/environment_spec.rb b/spec/unit/node/environment_spec.rb index b400865a2..be2980879 100755 --- a/spec/unit/node/environment_spec.rb +++ b/spec/unit/node/environment_spec.rb @@ -52,7 +52,8 @@ describe Puppet::Node::Environment do before do @env = Puppet::Node::Environment.new("dev") @collection = Puppet::Resource::TypeCollection.new(@env) - @collection.stubs(:perform_initial_import) + @env.stubs(:perform_initial_import).returns(Puppet::Parser::AST::Hostclass.new('')) + Thread.current[:known_resource_types] = nil end it "should create a resource type collection if none exists" do @@ -65,19 +66,46 @@ describe Puppet::Node::Environment do end it "should perform the initial import when creating a new collection" do - @collection.expects(:perform_initial_import) - Puppet::Resource::TypeCollection.expects(:new).returns @collection + @env = Puppet::Node::Environment.new("dev") + @env.expects(:perform_initial_import).returns(Puppet::Parser::AST::Hostclass.new('')) + @env.known_resource_types + end + + it "should return the same collection even if stale if it's the same thread" do + Puppet::Resource::TypeCollection.stubs(:new).returns @collection + @env.known_resource_types.stubs(:stale?).returns true + + @env.known_resource_types.should equal(@collection) + end + + it "should return the current thread associated collection if there is one" do + Thread.current[:known_resource_types] = @collection + @env.known_resource_types.should equal(@collection) + end + + it "should give to all threads the same collection if it didn't change" do + Puppet::Resource::TypeCollection.expects(:new).with(@env).returns @collection @env.known_resource_types + + t = Thread.new { + @env.known_resource_types.should equal(@collection) + } + t.join end - it "should create and return a new collection rather than returning a stale collection" do - @env.known_resource_types.expects(:stale?).returns true + it "should give to new threads a new collection if it isn't stale" do + Puppet::Resource::TypeCollection.expects(:new).with(@env).returns @collection + @env.known_resource_types.expects(:stale?).returns(true) Puppet::Resource::TypeCollection.expects(:new).returns @collection - @env.known_resource_types.should equal(@collection) + t = Thread.new { + @env.known_resource_types.should equal(@collection) + } + t.join end + end [:modulepath, :manifestdir].each do |setting| @@ -245,4 +273,56 @@ describe Puppet::Node::Environment do @helper.environment.name.should == :foo end end + + describe "when performing initial import" do + before do + @parser = stub 'parser', :file= => nil, :string => nil, :parse => nil + Puppet::Parser::Parser.stubs(:new).returns @parser + @env = Puppet::Node::Environment.new("env") + end + + it "should create a new parser instance" do + Puppet::Parser::Parser.expects(:new).returns @parser + @env.instance_eval { perform_initial_import } + end + + it "should set the parser's string to the 'code' setting and parse if code is available" do + Puppet.settings[:code] = "my code" + @parser.expects(:string=).with "my code" + @parser.expects(:parse) + @env.instance_eval { perform_initial_import } + end + + it "should set the parser's file to the 'manifest' setting and parse if no code is available and the manifest is available" do + File.stubs(:expand_path).with("/my/file").returns "/my/file" + File.expects(:exist?).with("/my/file").returns true + Puppet.settings[:manifest] = "/my/file" + @parser.expects(:file=).with "/my/file" + @parser.expects(:parse) + @env.instance_eval { perform_initial_import } + end + + it "should not attempt to load a manifest if none is present" do + File.stubs(:expand_path).with("/my/file").returns "/my/file" + File.expects(:exist?).with("/my/file").returns false + Puppet.settings[:manifest] = "/my/file" + @parser.expects(:file=).never + @parser.expects(:parse).never + @env.instance_eval { perform_initial_import } + end + + it "should fail helpfully if there is an error importing" do + File.stubs(:exist?).returns true + @parser.expects(:parse).raises ArgumentError + lambda { @env.instance_eval { perform_initial_import } }.should raise_error(Puppet::Error) + end + + it "should not do anything if the ignore_import settings is set" do + Puppet.settings[:ignoreimport] = true + @parser.expects(:string=).never + @parser.expects(:file=).never + @parser.expects(:parse).never + @env.instance_eval { perform_initial_import } + end + end end diff --git a/spec/unit/node/facts_spec.rb b/spec/unit/node/facts_spec.rb index a2f4ab9f0..cb2aa3dc7 100755 --- a/spec/unit/node/facts_spec.rb +++ b/spec/unit/node/facts_spec.rb @@ -88,9 +88,20 @@ describe Puppet::Node::Facts, "when indirecting" do @facts.save end - it "should default to the 'facter' terminus" do - Puppet::Node::Facts.indirection.terminus_class.should == :facter + describe "when the Puppet application is 'master'" do + it "should default to the 'yaml' terminus" do + pending "Cannot test the behavior of defaults in defaults.rb" + # Puppet::Node::Facts.indirection.terminus_class.should == :yaml + end end + + describe "when the Puppet application is not 'master'" do + it "should default to the 'facter' terminus" do + pending "Cannot test the behavior of defaults in defaults.rb" + # Puppet::Node::Facts.indirection.terminus_class.should == :facter + end + end + end describe "when storing and retrieving" do @@ -98,5 +109,29 @@ describe Puppet::Node::Facts, "when indirecting" do facts = Puppet::Node::Facts.new("me", "one" => "two", "three" => "four") facts.values[:_timestamp].should be_instance_of(Time) end + + describe "using pson" do + before :each do + @timestamp = Time.parse("Thu Oct 28 11:16:31 -0700 2010") + @expiration = Time.parse("Thu Oct 28 11:21:31 -0700 2010") + end + + it "should accept properly formatted pson" do + pson = %Q({"name": "foo", "expiration": "#{@expiration}", "timestamp": "#{@timestamp}", "values": {"a": "1", "b": "2", "c": "3"}}) + format = Puppet::Network::FormatHandler.format('pson') + facts = format.intern(Puppet::Node::Facts,pson) + facts.name.should == 'foo' + facts.expiration.should == @expiration + facts.values.should == {'a' => '1', 'b' => '2', 'c' => '3', :_timestamp => @timestamp} + end + + it "should generate properly formatted pson" do + Time.stubs(:now).returns(@timestamp) + facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3}) + facts.expiration = @expiration + pson = PSON.parse(facts.to_pson) + pson.should == {"name"=>"foo", "timestamp"=>@timestamp.to_s, "expiration"=>@expiration.to_s, "values"=>{"a"=>1, "b"=>2, "c"=>3}} + end + end end end diff --git a/spec/unit/parameter/value_collection_spec.rb b/spec/unit/parameter/value_collection_spec.rb index 78c2c5263..cb82d1517 100755 --- a/spec/unit/parameter/value_collection_spec.rb +++ b/spec/unit/parameter/value_collection_spec.rb @@ -68,12 +68,12 @@ describe Puppet::Parameter::ValueCollection do it "should correctly generate documentation for values" do @collection.newvalues :foo - @collection.doc.should be_include("Valid values are ``foo``") + @collection.doc.should be_include("Valid values are `foo`") end it "should correctly generate documentation for regexes" do @collection.newvalues %r{\w+} - @collection.doc.should be_include("Values can match ``/\\w+/``") + @collection.doc.should be_include("Values can match `/\\w+/`") end it "should be able to find the first matching value" do diff --git a/spec/unit/parser/ast/astarray_spec.rb b/spec/unit/parser/ast/astarray_spec.rb index f79d6c533..8794848b6 100755 --- a/spec/unit/parser/ast/astarray_spec.rb +++ b/spec/unit/parser/ast/astarray_spec.rb @@ -23,43 +23,26 @@ describe Puppet::Parser::AST::ASTArray do operator.evaluate(@scope) end - it "should evaluate childrens of type ASTArray" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields(item1) - - item1.expects(:safeevaluate).with(@scope).returns(123) - - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [123] - end - - it "should flatten children coming from children ASTArray" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields([item1]) - - item1.expects(:safeevaluate).with(@scope).returns(123) - - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [123] + it "should not flatten children coming from children ASTArray" do + item = Puppet::Parser::AST::String.new :value => 'foo' + inner_array = Puppet::Parser::AST::ASTArray.new :children => [item, item] + operator = Puppet::Parser::AST::ASTArray.new :children => [inner_array, inner_array] + operator.evaluate(@scope).should == [['foo', 'foo'], ['foo', 'foo']] end it "should not flatten the results of children evaluation" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields([item1]) - - item1.expects(:safeevaluate).with(@scope).returns([123]) + item = Puppet::Parser::AST::String.new :value => 'foo' + item.stubs(:evaluate).returns(['foo']) + operator = Puppet::Parser::AST::ASTArray.new :children => [item, item] + operator.evaluate(@scope).should == [['foo'], ['foo']] + end - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [[123]] + it "should discard nil results from children evaluation" do + item1 = Puppet::Parser::AST::String.new :value => 'foo' + item2 = Puppet::Parser::AST::String.new :value => 'foo' + item2.stubs(:evaluate).returns(nil) + operator = Puppet::Parser::AST::ASTArray.new :children => [item1, item2] + operator.evaluate(@scope).should == ['foo'] end it "should return a valid string with to_s" do diff --git a/spec/unit/parser/ast/collection_spec.rb b/spec/unit/parser/ast/collection_spec.rb index 3f7878a99..392a2c0f0 100755 --- a/spec/unit/parser/ast/collection_spec.rb +++ b/spec/unit/parser/ast/collection_spec.rb @@ -5,6 +5,8 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::Collection do before :each do @scope = stub_everything 'scope' + @mytype = stub_everything('mytype') + @scope.stubs(:find_resource_type).returns @mytype @compiler = stub_everything 'compile' @scope.stubs(:compiler).returns(@compiler) @@ -24,6 +26,8 @@ describe Puppet::Parser::AST::Collection do it "should instantiate a Collector for this type" do collection = Puppet::Parser::AST::Collection.new :form => :virtual, :type => "test" + @test_type = stub 'type', :name => 'test' + @scope.expects(:find_resource_type).with('test').returns @test_type Puppet::Parser::Collector.expects(:new).with(@scope, "test", nil, nil, :virtual) diff --git a/spec/unit/parser/ast/definition_spec.rb b/spec/unit/parser/ast/definition_spec.rb new file mode 100644 index 000000000..b7b2c851c --- /dev/null +++ b/spec/unit/parser/ast/definition_spec.rb @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Definition do + it "should make its context available through an accessor" do + definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) + definition.context.should == {:line => 5} + end + + describe "when instantiated" do + it "should create a definition with the proper type, name, context, and module name" do + definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) + instantiated_definitions = definition.instantiate('modname') + instantiated_definitions.length.should == 1 + instantiated_definitions[0].type.should == :definition + instantiated_definitions[0].name.should == 'foo' + instantiated_definitions[0].line.should == 5 + instantiated_definitions[0].module_name.should == 'modname' + end + end +end diff --git a/spec/unit/parser/ast/function_spec.rb b/spec/unit/parser/ast/function_spec.rb index c57c7f098..38e344157 100644 --- a/spec/unit/parser/ast/function_spec.rb +++ b/spec/unit/parser/ast/function_spec.rb @@ -61,20 +61,30 @@ describe Puppet::Parser::AST::Function do end it "should call the underlying ruby function" do - argument = stub 'arg', :safeevaluate => "nothing" + argument = stub 'arg', :safeevaluate => ["nothing"] Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument - @scope.expects(:function_exist).with("nothing") + @scope.expects(:function_exist).with(["nothing"]) + + func.evaluate(@scope) + end + + it "should convert :undef to '' in arguments" do + argument = stub 'arg', :safeevaluate => ["foo", :undef, "bar"] + Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) + func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument + + @scope.expects(:function_exist).with(["foo", "", "bar"]) func.evaluate(@scope) end it "should return the ruby function return for rvalue functions" do - argument = stub 'arg', :safeevaluate => "nothing" + argument = stub 'arg', :safeevaluate => ["nothing"] Puppet::Parser::Functions.stubs(:function).with("exist").returns(true) func = Puppet::Parser::AST::Function.new :name => "exist", :ftype => :statement, :arguments => argument - @scope.stubs(:function_exist).with("nothing").returns("returning") + @scope.stubs(:function_exist).with(["nothing"]).returns("returning") func.evaluate(@scope).should == "returning" end diff --git a/spec/unit/parser/ast/hostclass_spec.rb b/spec/unit/parser/ast/hostclass_spec.rb new file mode 100644 index 000000000..b22eba98b --- /dev/null +++ b/spec/unit/parser/ast/hostclass_spec.rb @@ -0,0 +1,73 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Hostclass do + def ast + Puppet::Parser::AST + end + + def newarray(*elems) + ast::ASTArray.new({}).push(*elems) + end + + it "should make its name and context available through accessors" do + hostclass = ast::Hostclass.new('foo', :line => 5) + hostclass.name.should == 'foo' + hostclass.context.should == {:line => 5} + end + + it "should make its code available through an accessor" do + code = newarray + hostclass = ast::Hostclass.new('foo', :code => code) + hostclass.code.should be_equal(code) + end + + describe "when instantiated" do + it "should create a class with the proper type, code, name, context, and module name" do + code = newarray + hostclass = ast::Hostclass.new('foo', :code => code, :line => 5) + instantiated_class = hostclass.instantiate('modname')[0] + instantiated_class.type.should == :hostclass + instantiated_class.name.should == 'foo' + instantiated_class.code.should be_equal(code) + instantiated_class.line.should == 5 + instantiated_class.module_name.should == 'modname' + end + + it "should instantiate all nested classes, defines, and nodes with the same module name." do + nested_objects = newarray(ast::Hostclass.new('foo::child1'), + ast::Definition.new('foo::child2'), + ast::Definition.new('child3')) + hostclass = ast::Hostclass.new('foo', :code => nested_objects) + instantiated_classes = hostclass.instantiate('modname') + instantiated_classes.length.should == 4 + instantiated_classes[0].name.should == 'foo' + instantiated_classes[1].name.should == 'foo::child1' + instantiated_classes[2].name.should == 'foo::child2' + instantiated_classes[3].name.should == 'child3' + instantiated_classes.each { |cls| cls.module_name.should == 'modname' } + end + + it "should handle a nested class that contains its own nested classes." do + foo_bar_baz = ast::Hostclass.new('foo::bar::baz') + foo_bar = ast::Hostclass.new('foo::bar', :code => newarray(foo_bar_baz)) + foo = ast::Hostclass.new('foo', :code => newarray(foo_bar)) + instantiated_classes = foo.instantiate('') + instantiated_classes.length.should == 3 + instantiated_classes[0].name.should == 'foo' + instantiated_classes[1].name.should == 'foo::bar' + instantiated_classes[2].name.should == 'foo::bar::baz' + end + + it "should skip nested elements that are not classes, definitions, or nodes." do + func = ast::Function.new(:name => 'biz', :arguments => newarray(ast::Name.new(:value => 'baz'))) + foo = ast::Hostclass.new('foo', :code => newarray(func)) + instantiated_classes = foo.instantiate('') + instantiated_classes.length.should == 1 + instantiated_classes[0].should be_a(Puppet::Resource::Type) + instantiated_classes[0].name.should == 'foo' + end + end +end + diff --git a/spec/unit/parser/ast/leaf_spec.rb b/spec/unit/parser/ast/leaf_spec.rb index 5bdca67fa..a19c24115 100755 --- a/spec/unit/parser/ast/leaf_spec.rb +++ b/spec/unit/parser/ast/leaf_spec.rb @@ -47,6 +47,10 @@ describe Puppet::Parser::AST::String do value = stub 'value', :is_a? => true, :to_s => "ab" Puppet::Parser::AST::String.new( :value => value ).to_s.should == "\"ab\"" end + it "should return a dup of its value" do + value = "" + Puppet::Parser::AST::String.new( :value => value ).evaluate(stub('scope')).should_not be_equal(value) + end end end @@ -132,6 +136,22 @@ describe Puppet::Parser::AST::HashOrArrayAccess do access.evaluate(@scope).should == "val2" end + it "should be able to return an array member when index is a stringified number" do + @scope.stubs(:lookupvar).with("a").returns(["val1", "val2", "val3"]) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "1" ) + + access.evaluate(@scope).should == "val2" + end + + it "should raise an error when accessing an array with a key" do + @scope.stubs(:lookupvar).with("a").returns(["val1", "val2", "val3"]) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) + + lambda { access.evaluate(@scope) }.should raise_error + end + it "should be able to return an hash value" do @scope.stubs(:lookupvar).with("a").returns({ "key1" => "val1", "key2" => "val2", "key3" => "val3" }) @@ -140,6 +160,14 @@ describe Puppet::Parser::AST::HashOrArrayAccess do access.evaluate(@scope).should == "val2" end + it "should be able to return an hash value with a numerical key" do + @scope.stubs(:lookupvar).with("a").returns({ "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" }) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "45" ) + + access.evaluate(@scope).should == "45" + end + it "should raise an error if the variable lookup didn't return an hash or an array" do @scope.stubs(:lookupvar).with("a").returns("I'm a string") @@ -191,6 +219,24 @@ describe Puppet::Parser::AST::HashOrArrayAccess do scope.lookupvar("a").should be_include("b") end + it "should raise an error when assigning an array element with a key" do + @scope.stubs(:lookupvar).with("a").returns([]) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) + + lambda { access.assign(@scope, "test") }.should raise_error + end + + it "should be able to return an array member when index is a stringified number" do + scope = Puppet::Parser::Scope.new + scope.setvar("a", []) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "0" ) + + access.assign(scope, "val2") + scope.lookupvar("a").should == ["val2"] + end + it "should raise an error when trying to overwrite an hash value" do @scope.stubs(:lookupvar).with("a").returns({ "key" => [ "a" , "b" ]}) access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") diff --git a/spec/unit/parser/ast/node_spec.rb b/spec/unit/parser/ast/node_spec.rb new file mode 100644 index 000000000..3e8017de0 --- /dev/null +++ b/spec/unit/parser/ast/node_spec.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Node do + describe "when instantiated" do + it "should make its names and context available through accessors" do + node = Puppet::Parser::AST::Node.new(['foo', 'bar'], :line => 5) + node.names.should == ['foo', 'bar'] + node.context.should == {:line => 5} + end + + it "should create a node with the proper type, name, context, and module name" do + node = Puppet::Parser::AST::Node.new(['foo'], :line => 5) + instantiated_nodes = node.instantiate('modname') + instantiated_nodes.length.should == 1 + instantiated_nodes[0].type.should == :node + instantiated_nodes[0].name.should == 'foo' + instantiated_nodes[0].line.should == 5 + instantiated_nodes[0].module_name.should == 'modname' + end + + it "should handle multiple names" do + node = Puppet::Parser::AST::Node.new(['foo', 'bar']) + instantiated_nodes = node.instantiate('modname') + instantiated_nodes.length.should == 2 + instantiated_nodes[0].name.should == 'foo' + instantiated_nodes[1].name.should == 'bar' + end + end +end diff --git a/spec/unit/parser/ast/resource_reference_spec.rb b/spec/unit/parser/ast/resource_reference_spec.rb index 7b48119f4..93419d963 100755 --- a/spec/unit/parser/ast/resource_reference_spec.rb +++ b/spec/unit/parser/ast/resource_reference_spec.rb @@ -32,11 +32,6 @@ describe Puppet::Parser::AST::ResourceReference do ] end - it "should pass its scope's namespaces to all created resource references" do - @scope.add_namespace "foo" - newref("File", "/tmp/yay").evaluate(@scope).namespaces.should == ["foo"] - end - it "should return a correct representation when converting to string" do type = stub 'type', :is_a? => true, :to_s => "file" title = stub 'title', :is_a? => true, :to_s => "[/tmp/a, /tmp/b]" diff --git a/spec/unit/parser/ast/resource_spec.rb b/spec/unit/parser/ast/resource_spec.rb index 58ffae925..3f7fa229a 100755 --- a/spec/unit/parser/ast/resource_spec.rb +++ b/spec/unit/parser/ast/resource_spec.rb @@ -5,116 +5,180 @@ require File.dirname(__FILE__) + '/../../../spec_helper' describe Puppet::Parser::AST::Resource do ast = Puppet::Parser::AST - before :each do - @title = Puppet::Parser::AST::String.new(:value => "mytitle") - @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @scope = Puppet::Parser::Scope.new(:compiler => @compiler) - @scope.stubs(:resource).returns(stub_everything) - @resource = ast::Resource.new(:title => @title, :type => "file", :parameters => ast::ASTArray.new(:children => []) ) - @resource.stubs(:qualified_type).returns("Resource") - end + describe "for builtin types" do + before :each do + @title = Puppet::Parser::AST::String.new(:value => "mytitle") + @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) + @scope = Puppet::Parser::Scope.new(:compiler => @compiler) + @scope.stubs(:resource).returns(stub_everything) + @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) + @resource = ast::Resource.new(:type => "file", :instances => ast::ASTArray.new(:children => [@instance])) + @resource.stubs(:qualified_type).returns("Resource") + end - it "should evaluate all its parameters" do - param = stub 'param' - param.expects(:safeevaluate).with(@scope).returns Puppet::Parser::Resource::Param.new(:name => "myparam", :value => "myvalue", :source => stub("source")) - @resource.stubs(:parameters).returns [param] + it "should evaluate all its parameters" do + param = stub 'param' + param.expects(:safeevaluate).with(@scope).returns Puppet::Parser::Resource::Param.new(:name => "myparam", :value => "myvalue", :source => stub("source")) + @instance.stubs(:parameters).returns [param] - @resource.evaluate(@scope) - end - - it "should evaluate its title" do - @resource.evaluate(@scope)[0].title.should == "mytitle" - end + @resource.evaluate(@scope) + end - it "should flatten the titles array" do - titles = [] - %w{one two}.each do |title| - titles << Puppet::Parser::AST::String.new(:value => title) + it "should evaluate its title" do + @resource.evaluate(@scope)[0].title.should == "mytitle" end - array = Puppet::Parser::AST::ASTArray.new(:children => titles) + it "should flatten the titles array" do + titles = [] + %w{one two}.each do |title| + titles << Puppet::Parser::AST::String.new(:value => title) + end - @resource.title = array - result = @resource.evaluate(@scope).collect { |r| r.title } - result.should be_include("one") - result.should be_include("two") - end + array = Puppet::Parser::AST::ASTArray.new(:children => titles) - it "should create and return one resource objects per title" do - titles = [] - %w{one two}.each do |title| - titles << Puppet::Parser::AST::String.new(:value => title) + @instance.title = array + result = @resource.evaluate(@scope).collect { |r| r.title } + result.should be_include("one") + result.should be_include("two") end - array = Puppet::Parser::AST::ASTArray.new(:children => titles) + it "should create and return one resource objects per title" do + titles = [] + %w{one two}.each do |title| + titles << Puppet::Parser::AST::String.new(:value => title) + end - @resource.title = array - result = @resource.evaluate(@scope).collect { |r| r.title } - result.should be_include("one") - result.should be_include("two") - end + array = Puppet::Parser::AST::ASTArray.new(:children => titles) - it "should handover resources to the compiler" do - titles = [] - %w{one two}.each do |title| - titles << Puppet::Parser::AST::String.new(:value => title) + @instance.title = array + result = @resource.evaluate(@scope).collect { |r| r.title } + result.should be_include("one") + result.should be_include("two") end - array = Puppet::Parser::AST::ASTArray.new(:children => titles) + it "should implicitly iterate over instances" do + new_title = Puppet::Parser::AST::String.new(:value => "other_title") + new_instance = ast::ResourceInstance.new(:title => new_title, :parameters => ast::ASTArray.new(:children => [])) + @resource.instances.push(new_instance) + @resource.evaluate(@scope).collect { |r| r.title }.should == ["mytitle", "other_title"] + end - @resource.title = array - result = @resource.evaluate(@scope) + it "should handover resources to the compiler" do + titles = [] + %w{one two}.each do |title| + titles << Puppet::Parser::AST::String.new(:value => title) + end - result.each do |res| - @compiler.catalog.resource(res.ref).should be_instance_of(Puppet::Parser::Resource) - end - end - it "should generate virtual resources if it is virtual" do - @resource.virtual = true + array = Puppet::Parser::AST::ASTArray.new(:children => titles) - result = @resource.evaluate(@scope) - result[0].should be_virtual - end + @instance.title = array + result = @resource.evaluate(@scope) - it "should generate virtual and exported resources if it is exported" do - @resource.exported = true + result.each do |res| + @compiler.catalog.resource(res.ref).should be_instance_of(Puppet::Parser::Resource) + end + end - result = @resource.evaluate(@scope) - result[0].should be_virtual - result[0].should be_exported - end + it "should generate virtual resources if it is virtual" do + @resource.virtual = true - # Related to #806, make sure resources always look up the full path to the resource. - describe "when generating qualified resources" do - before do - @scope = Puppet::Parser::Scope.new :compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) - @parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new) - @parser.newdefine "one" - @parser.newdefine "one::two" - @parser.newdefine "three" - @twoscope = @scope.newscope(:namespace => "one") - @twoscope.resource = @scope.resource + result = @resource.evaluate(@scope) + result[0].should be_virtual end - def resource(type, params = nil) - params ||= Puppet::Parser::AST::ASTArray.new(:children => []) - Puppet::Parser::AST::Resource.new(:type => type, :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) + it "should generate virtual and exported resources if it is exported" do + @resource.exported = true + + result = @resource.evaluate(@scope) + result[0].should be_virtual + result[0].should be_exported end - it "should be able to generate resources with fully qualified type information" do - resource("two").evaluate(@twoscope)[0].type.should == "One::Two" + # Related to #806, make sure resources always look up the full path to the resource. + describe "when generating qualified resources" do + before do + @scope = Puppet::Parser::Scope.new :compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) + @parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new) + ["one", "one::two", "three"].each do |name| + @parser.environment.known_resource_types.add(Puppet::Resource::Type.new(:definition, name, {})) + end + @twoscope = @scope.newscope(:namespace => "one") + @twoscope.resource = @scope.resource + end + + def resource(type, params = nil) + params ||= Puppet::Parser::AST::ASTArray.new(:children => []) + instance = Puppet::Parser::AST::ResourceInstance.new( + :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) + Puppet::Parser::AST::Resource.new(:type => type, + :instances => Puppet::Parser::AST::ASTArray.new(:children => [instance])) + end + + it "should be able to generate resources with fully qualified type information" do + resource("two").evaluate(@twoscope)[0].type.should == "One::Two" + end + + it "should be able to generate resources with unqualified type information" do + resource("one").evaluate(@twoscope)[0].type.should == "One" + end + + it "should correctly generate resources that can look up builtin types" do + resource("file").evaluate(@twoscope)[0].type.should == "File" + end + + it "should correctly generate resources that can look up defined classes by title" do + @scope.known_resource_types.add_hostclass Puppet::Resource::Type.new(:hostclass, "Myresource", {}) + @scope.compiler.stubs(:evaluate_classes) + res = resource("class").evaluate(@twoscope)[0] + res.type.should == "Class" + res.title.should == "Myresource" + end + + it "should evaluate parameterized classes when they are instantiated" do + @scope.known_resource_types.add_hostclass Puppet::Resource::Type.new(:hostclass, "Myresource", {}) + @scope.compiler.expects(:evaluate_classes).with(['myresource'],@twoscope,false) + resource("class").evaluate(@twoscope)[0] + end + + it "should fail for resource types that do not exist" do + lambda { resource("nosuchtype").evaluate(@twoscope) }.should raise_error(Puppet::ParseError) + end end + end - it "should be able to generate resources with unqualified type information" do - resource("one").evaluate(@twoscope)[0].type.should == "One" + describe "for class resources" do + before do + @title = Puppet::Parser::AST::String.new(:value => "classname") + @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) + @scope = Puppet::Parser::Scope.new(:compiler => @compiler) + @scope.stubs(:resource).returns(stub_everything) + @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) + @resource = ast::Resource.new(:type => "Class", :instances => ast::ASTArray.new(:children => [@instance])) + @resource.stubs(:qualified_type).returns("Resource") + @type = Puppet::Resource::Type.new(:hostclass, "classname") + @compiler.known_resource_types.add(@type) end - it "should correctly generate resources that can look up builtin types" do - resource("file").evaluate(@twoscope)[0].type.should == "File" + it "should instantiate the class" do + @compiler.stubs(:evaluate_classes) + result = @resource.evaluate(@scope) + result.length.should == 1 + result.first.ref.should == "Class[Classname]" + @compiler.catalog.resource("Class[Classname]").should equal(result.first) end - it "should fail for resource types that do not exist" do - lambda { resource("nosuchtype").evaluate(@twoscope) }.should raise_error(Puppet::ParseError) + it "should cause its parent to be evaluated" do + parent_type = Puppet::Resource::Type.new(:hostclass, "parentname") + @compiler.stubs(:evaluate_classes) + @compiler.known_resource_types.add(parent_type) + @type.parent = "parentname" + result = @resource.evaluate(@scope) + result.length.should == 1 + result.first.ref.should == "Class[Classname]" + @compiler.catalog.resource("Class[Classname]").should equal(result.first) + @compiler.catalog.resource("Class[Parentname]").should be_instance_of(Puppet::Parser::Resource) end + end + end diff --git a/spec/unit/parser/collector_spec.rb b/spec/unit/parser/collector_spec.rb index 15808d6ff..908cda63a 100755 --- a/spec/unit/parser/collector_spec.rb +++ b/spec/unit/parser/collector_spec.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' require 'puppet/parser/collector' describe Puppet::Parser::Collector, "when initializing" do diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index e8c06dd0b..95f3853e2 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -430,7 +430,18 @@ describe Puppet::Parser::Compiler do lambda { @compiler.add_resource(@scope, resource) }.should raise_error(ArgumentError) end - it "should add edges from the class resources to the main stage if no stage is specified" do + it "should add edges from the class resources to the parent's stage if no stage is specified" do + main = @compiler.catalog.resource(:stage, :main) + foo_stage = resource(:stage, :foo_stage) + @compiler.add_resource(@scope, foo_stage) + resource = resource(:class, "foo") + @scope.stubs(:resource).returns(:stage => :foo_stage) + @compiler.add_resource(@scope, resource) + + @compiler.catalog.should be_edge(foo_stage, resource) + end + + it "should add edges from top-level class resources to the main stage if no stage is specified" do main = @compiler.catalog.resource(:stage, :main) resource = resource(:class, "foo") @compiler.add_resource(@scope, resource) @@ -569,7 +580,7 @@ describe Puppet::Parser::Compiler do it "should evaluate each class" do @compiler.catalog.stubs(:tag) - @class.expects(:mk_plain_resource).with(@scope) + @class.expects(:ensure_in_catalog).with(@scope) @scope.stubs(:class_scope).with(@class) @compiler.evaluate_classes(%w{myclass}, @scope) @@ -580,7 +591,7 @@ describe Puppet::Parser::Compiler do @resource.expects(:evaluate).never - @class.expects(:mk_plain_resource).returns(@resource) + @class.expects(:ensure_in_catalog).returns(@resource) @scope.stubs(:class_scope).with(@class) @compiler.evaluate_classes(%w{myclass}, @scope) @@ -590,7 +601,7 @@ describe Puppet::Parser::Compiler do @compiler.catalog.stubs(:tag) @resource.expects(:evaluate) - @class.expects(:mk_plain_resource).returns(@resource) + @class.expects(:ensure_in_catalog).returns(@resource) @scope.stubs(:class_scope).with(@class) @compiler.evaluate_classes(%w{myclass}, @scope, false) @@ -627,7 +638,7 @@ describe Puppet::Parser::Compiler do @scope.stubs(:class_scope).with(@class) Puppet::Parser::Resource.stubs(:new).returns(@resource) - @class.stubs :mk_plain_resource + @class.stubs :ensure_in_catalog @compiler.evaluate_classes(%w{myclass notfound}, @scope).should == %w{myclass} end end @@ -667,7 +678,7 @@ describe Puppet::Parser::Compiler do @compiler.known_resource_types.stubs(:node).with("c").returns(node_class) node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil, :type => "node" - node_class.expects(:mk_plain_resource).returns(node_resource) + node_class.expects(:ensure_in_catalog).returns(node_resource) @compiler.compile end @@ -677,7 +688,7 @@ describe Puppet::Parser::Compiler do @compiler.known_resource_types.stubs(:node).with("default").returns(node_class) node_resource = stub 'node resource', :ref => "Node[default]", :evaluate => nil, :type => "node" - node_class.expects(:mk_plain_resource).returns(node_resource) + node_class.expects(:ensure_in_catalog).returns(node_resource) @compiler.compile end @@ -687,7 +698,7 @@ describe Puppet::Parser::Compiler do @compiler.known_resource_types.stubs(:node).with("c").returns(node_class) node_resource = stub 'node resource', :ref => "Node[c]", :type => "node" - node_class.expects(:mk_plain_resource).returns(node_resource) + node_class.expects(:ensure_in_catalog).returns(node_resource) node_resource.expects(:evaluate) @@ -696,7 +707,7 @@ describe Puppet::Parser::Compiler do it "should set the node's scope as the top scope" do node_resource = stub 'node resource', :ref => "Node[c]", :evaluate => nil, :type => "node" - node_class = stub 'node', :name => "c", :mk_plain_resource => node_resource + node_class = stub 'node', :name => "c", :ensure_in_catalog => node_resource @compiler.known_resource_types.stubs(:node).with("c").returns(node_class) diff --git a/spec/unit/parser/files_spec.rb b/spec/unit/parser/files_spec.rb index fcfbfa613..3eb0db07e 100644 --- a/spec/unit/parser/files_spec.rb +++ b/spec/unit/parser/files_spec.rb @@ -154,7 +154,7 @@ describe Puppet::Parser::Files do it "should match against provided fully qualified patterns" do pattern = @basepath + "/fully/qualified/pattern/*" - Dir.expects(:glob).with(pattern+'{,.pp,.rb}').returns(%w{my file list}) + Dir.expects(:glob).with(pattern+'{.pp,.rb}').returns(%w{my file list}) Puppet::Parser::Files.find_manifests(pattern)[1].should == %w{my file list} end @@ -168,7 +168,7 @@ describe Puppet::Parser::Files do pattern = @basepath + "/fully/qualified/pattern/*" file = @basepath + "/my/file" dir = @basepath + "/my/directory" - Dir.expects(:glob).with(pattern+'{,.pp,.rb}').returns([file, dir]) + Dir.expects(:glob).with(pattern+'{.pp,.rb}').returns([file, dir]) FileTest.expects(:directory?).with(file).returns(false) FileTest.expects(:directory?).with(dir).returns(true) Puppet::Parser::Files.find_manifests(pattern)[1].should == [file] @@ -176,7 +176,7 @@ describe Puppet::Parser::Files do it "should return files once only" do pattern = @basepath + "/fully/qualified/pattern/*" - Dir.expects(:glob).with(pattern+'{,.pp,.rb}').returns(%w{one two one}) + Dir.expects(:glob).with(pattern+'{.pp,.rb}').returns(%w{one two one}) Puppet::Parser::Files.find_manifests(pattern)[1].should == %w{one two} end end diff --git a/spec/unit/parser/functions/extlookup_spec.rb b/spec/unit/parser/functions/extlookup_spec.rb new file mode 100755 index 000000000..a3dcaa742 --- /dev/null +++ b/spec/unit/parser/functions/extlookup_spec.rb @@ -0,0 +1,95 @@ +#! /usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' +require 'tempfile' + +describe "the extlookup function" do + + before :each do + @scope = Puppet::Parser::Scope.new + + @scope.stubs(:environment).returns(Puppet::Node::Environment.new('production')) + Puppet::Parser::Functions.function("extlookup") + end + + it "should exist" do + Puppet::Parser::Functions.function("extlookup").should == "function_extlookup" + end + + it "should raise a ParseError if there is less than 1 arguments" do + lambda { @scope.function_extlookup([]) }.should( raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError if there is more than 3 arguments" do + lambda { @scope.function_extlookup(["foo", "bar", "baz", "gazonk"]) }.should( raise_error(Puppet::ParseError)) + end + + it "should return the default" do + result = @scope.function_extlookup([ "key", "default"]) + result.should == "default" + end + + it "should lookup the key in a supplied datafile" do + t = Tempfile.new('extlookup.csv') do + t.puts 'key,value' + t.puts 'nonkey,nonvalue' + t.close + + result = @scope.function_extlookup([ "key", "default", t.path]) + result.should == "value" + end + end + + it "should return an array if the datafile contains more than two columns" do + t = Tempfile.new('extlookup.csv') do + t.puts 'key,value1,value2' + t.puts 'nonkey,nonvalue,nonvalue' + t.close + + result = @scope.function_extlookup([ "key", "default", t.path]) + result.should == ["value1", "value2"] + end + end + + it "should raise an error if there's no matching key and no default" do + t = Tempfile.new('extlookup.csv') do + t.puts 'key,value' + t.puts 'nonkey,nonvalue' + t.close + + result = @scope.function_extlookup([ "key", nil, t.path]) + result.should == "value" + end + end + + describe "should look in $extlookup_datadir for data files listed by $extlookup_precedence" do + before do + @scope.stubs(:lookupvar).with('extlookup_datadir').returns("/tmp") + File.open("/tmp/one.csv","w"){|one| one.puts "key,value1" } + File.open("/tmp/two.csv","w") do |two| + two.puts "key,value2" + two.puts "key2,value_two" + end + end + + it "when the key is in the first file" do + @scope.stubs(:lookupvar).with('extlookup_precedence').returns(["one","two"]) + result = @scope.function_extlookup([ "key" ]) + result.should == "value1" + end + + it "when the key is in the second file" do + @scope.stubs(:lookupvar).with('extlookup_precedence').returns(["one","two"]) + result = @scope.function_extlookup([ "key2" ]) + result.should == "value_two" + end + + it "should not modify extlookup_precedence data" do + variable = '%{fqdn}' + @scope.stubs(:lookupvar).with('extlookup_precedence').returns([variable,"one"]) + @scope.stubs(:lookupvar).with('fqdn').returns('myfqdn') + result = @scope.function_extlookup([ "key" ]) + variable.should == '%{fqdn}' + end + end +end diff --git a/spec/unit/parser/functions/include_spec.rb b/spec/unit/parser/functions/include_spec.rb new file mode 100644 index 000000000..4f609b055 --- /dev/null +++ b/spec/unit/parser/functions/include_spec.rb @@ -0,0 +1,33 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "the 'include' function" do + + before :each do + Puppet::Node::Environment.stubs(:current).returns(nil) + @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) + @scope = Puppet::Parser::Scope.new(:compiler => @compiler) + end + + it "should exist" do + Puppet::Parser::Functions.function("include").should == "function_include" + end + + it "should include a single class" do + inc = "foo" + @compiler.expects(:evaluate_classes).with {|klasses,parser,lazy| klasses == [inc]}.returns([inc]) + @scope.function_include("foo") + end + + it "should include multiple classes" do + inc = ["foo","bar"] + @compiler.expects(:evaluate_classes).with {|klasses,parser,lazy| klasses == inc}.returns(inc) + @scope.function_include(["foo","bar"]) + end + + it "should not lazily evaluate the included class" do + @compiler.expects(:evaluate_classes).with {|klasses,parser,lazy| lazy == false}.returns("foo") + @scope.function_include("foo") + end +end diff --git a/spec/unit/parser/functions/require_spec.rb b/spec/unit/parser/functions/require_spec.rb index bd42fa579..49c4bbf74 100755 --- a/spec/unit/parser/functions/require_spec.rb +++ b/spec/unit/parser/functions/require_spec.rb @@ -6,7 +6,7 @@ describe "the require function" do before :each do @catalog = stub 'catalog' - @compiler = stub 'compiler', :catalog => @catalog + @compiler = stub 'compiler', :catalog => @catalog, :environment => nil @scope = Puppet::Parser::Scope.new @scope.stubs(:findresource) diff --git a/spec/unit/parser/functions/tag_spec.rb b/spec/unit/parser/functions/tag_spec.rb index ff37badbb..dac134134 100755 --- a/spec/unit/parser/functions/tag_spec.rb +++ b/spec/unit/parser/functions/tag_spec.rb @@ -6,6 +6,7 @@ describe "the 'tag' function" do before :each do @scope = Puppet::Parser::Scope.new + @scope.stubs(:environment).returns(nil) end it "should exist" do diff --git a/spec/unit/parser/lexer_spec.rb b/spec/unit/parser/lexer_spec.rb index d3d2a0a31..d52add399 100755 --- a/spec/unit/parser/lexer_spec.rb +++ b/spec/unit/parser/lexer_spec.rb @@ -30,6 +30,14 @@ describe Puppet::Parser::Lexer do @lexer.line.should == 10 end + + it "should not think the terminator is escaped, when preceeded by an even number of backslashes" do + @lexer.line = 10 + @lexer.string = "here\nis\nthe\nstring\\\\'with\nextra\njunk" + @lexer.slurpstring("'") + + @lexer.line.should == 13 + end end end @@ -410,8 +418,13 @@ describe Puppet::Parser::Lexer,"when lexing strings" do %q{'single quoted string')} => [[:STRING,'single quoted string']], %q{"double quoted string"} => [[:STRING,'double quoted string']], %q{'single quoted string with an escaped "\\'"'} => [[:STRING,'single quoted string with an escaped "\'"']], + %q{'single quoted string with an escaped "\$"'} => [[:STRING,'single quoted string with an escaped "\$"']], + %q{'single quoted string with an escaped "\."'} => [[:STRING,'single quoted string with an escaped "\."']], + %q{'single quoted string with an escaped "\n"'} => [[:STRING,'single quoted string with an escaped "\n"']], + %q{'single quoted string with an escaped "\\\\"'} => [[:STRING,'single quoted string with an escaped "\\\\"']], %q{"string with an escaped '\\"'"} => [[:STRING,"string with an escaped '\"'"]], %q{"string with an escaped '\\$'"} => [[:STRING,"string with an escaped '$'"]], + %Q{"string with a line ending with a backslash: \\\nfoo"} => [[:STRING,"string with a line ending with a backslash: foo"]], %q{"string with $v (but no braces)"} => [[:DQPRE,"string with "],[:VARIABLE,'v'],[:DQPOST,' (but no braces)']], %q["string with ${v} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,'v'],[:DQPOST,' in braces']], %q["string with ${qualified::var} in braces"] => [[:DQPRE,"string with "],[:VARIABLE,'qualified::var'],[:DQPOST,' in braces']], @@ -616,6 +629,12 @@ describe "Puppet::Parser::Lexer in the old tests" do @lexer.namespace.should == "base::sub" end + it "should not put class instantiation on the namespace" do + @lexer.string = "class base { class sub { class { mode" + @lexer.fullscan + @lexer.namespace.should == "base::sub" + end + it "should correctly handle fully qualified names" do @lexer.string = "class base { class sub::more {" @lexer.fullscan @@ -634,7 +653,6 @@ end require 'puppettest/support/utils' describe "Puppet::Parser::Lexer in the old tests when lexing example files" do - extend PuppetTest extend PuppetTest::Support::Utils textfiles do |file| it "should correctly lex #{file}" do diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 0657ab37a..ab43194e9 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Parser do - ast = Puppet::Parser::AST + Puppet::Parser::AST before :each do @known_resource_types = Puppet::Resource::TypeCollection.new("development") @@ -52,15 +52,6 @@ describe Puppet::Parser do @parser.file = "/my/file.rb" @parser.parse end - - describe "in ruby" do - it "should use the ruby interpreter to load the file" do - @parser.file = "/my/file.rb" - @parser.expects(:require).with "/my/file.rb" - - @parser.parse_ruby_file - end - end end describe "when parsing append operator" do @@ -73,35 +64,37 @@ describe Puppet::Parser do lambda { @parser.parse("$var += ") }.should raise_error end - it "should call ast::VarDef with append=true" do - ast::VarDef.expects(:new).with { |h| h[:append] == true } - @parser.parse("$var += 2") + it "should create ast::VarDef with append=true" do + vardef = @parser.parse("$var += 2").code[0] + vardef.should be_a(Puppet::Parser::AST::VarDef) + vardef.append.should == true end it "should work with arrays too" do - ast::VarDef.expects(:new).with { |h| h[:append] == true } - @parser.parse("$var += ['test']") + vardef = @parser.parse("$var += ['test']").code[0] + vardef.should be_a(Puppet::Parser::AST::VarDef) + vardef.append.should == true end end describe "when parsing 'if'" do it "not, it should create the correct ast objects" do - ast::Not.expects(:new).with { |h| h[:value].is_a?(ast::Boolean) } + Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } @parser.parse("if ! true { $var = 1 }") end it "boolean operation, it should create the correct ast objects" do - ast::BooleanOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Boolean) and h[:lval].is_a?(ast::Boolean) and h[:operator]=="or" + Puppet::Parser::AST::BooleanOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Boolean) and h[:lval].is_a?(Puppet::Parser::AST::Boolean) and h[:operator]=="or" } @parser.parse("if true or true { $var = 1 }") end it "comparison operation, it should create the correct ast objects" do - ast::ComparisonOperator.expects(:new).with { - |h| h[:lval].is_a?(ast::Name) and h[:rval].is_a?(ast::Name) and h[:operator]=="<" + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="<" } @parser.parse("if 1 < 2 { $var = 1 }") @@ -112,13 +105,13 @@ describe Puppet::Parser do describe "when parsing if complex expressions" do it "should create a correct ast tree" do aststub = stub_everything 'ast' - ast::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]==">" + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]==">" }.returns(aststub) - ast::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]=="==" + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="==" }.returns(aststub) - ast::BooleanOperator.expects(:new).with { + Puppet::Parser::AST::BooleanOperator.expects(:new).with { |h| h[:rval]==aststub and h[:lval]==aststub and h[:operator]=="and" } @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }") @@ -141,9 +134,8 @@ describe Puppet::Parser do end it "should create an ast::ResourceReference" do - ast::Resource.stubs(:new) - ast::ResourceReference.expects(:new).with { |arg| - arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(ast::ASTArray) + Puppet::Parser::AST::ResourceReference.expects(:new).with { |arg| + arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(Puppet::Parser::AST::ASTArray) } @parser.parse('exec { test: command => File["a","b"] }') end @@ -160,10 +152,14 @@ describe Puppet::Parser do end it "should create an ast::ResourceOverride" do - ast::ResourceOverride.expects(:new).with { |arg| - arg[:line]==1 and arg[:object].is_a?(ast::ResourceReference) and arg[:parameters].is_a?(ast::ResourceParam) - } - @parser.parse('Resource["title1","title2"] { param => value }') + #Puppet::Parser::AST::ResourceOverride.expects(:new).with { |arg| + # arg[:line]==1 and arg[:object].is_a?(Puppet::Parser::AST::ResourceReference) and arg[:parameters].is_a?(Puppet::Parser::AST::ResourceParam) + #} + ro = @parser.parse('Resource["title1","title2"] { param => value }').code[0] + ro.should be_a(Puppet::Parser::AST::ResourceOverride) + ro.line.should == 1 + ro.object.should be_a(Puppet::Parser::AST::ResourceReference) + ro.parameters[0].should be_a(Puppet::Parser::AST::ResourceParam) end end @@ -183,17 +179,17 @@ describe Puppet::Parser do end it "should create a nop node for empty branch" do - ast::Nop.expects(:new) + Puppet::Parser::AST::Nop.expects(:new) @parser.parse("if true { }") end it "should create a nop node for empty else branch" do - ast::Nop.expects(:new) + Puppet::Parser::AST::Nop.expects(:new) @parser.parse("if true { notice('test') } else { }") end it "should build a chain of 'ifs' if there's an 'elsif'" do - ast = @parser.parse(<<-PP) + lambda { @parser.parse(<<-PP) }.should_not raise_error if true { notice('test') } elsif true {} else { } PP end @@ -278,33 +274,22 @@ describe Puppet::Parser do it "should prefer provided options over AST context" do @class.expects(:new).with { |opts| opts[:file] == "/bar" } - @parser.expects(:ast_context).returns :file => "/foo" + @lexer.expects(:file).returns "/foo" @parser.ast(@class, :file => "/bar") end it "should include docs when the AST class uses them" do @class.expects(:use_docs).returns true @class.stubs(:new) - @parser.expects(:ast_context).with(true).returns({}) + @parser.expects(:ast_context).with{ |a| a[0] == true }.returns({}) @parser.ast(@class, :file => "/bar") end - end - - describe "when creating a node" do - before :each do - @lexer = stub 'lexer' - @lexer.stubs(:getcomment) - @parser.stubs(:lexer).returns(@lexer) - @node = stub_everything 'node' - @parser.stubs(:ast_context).returns({}) - @parser.stubs(:node).returns(nil) - - @nodename = stub 'nodename', :is_a? => false, :value => "foo" - @nodename.stubs(:is_a?).with(Puppet::Parser::AST::HostName).returns(true) - end - it "should return an array of nodes" do - @parser.newnode(@nodename).should be_instance_of(Array) + it "should get docs from lexer using the correct AST line number" do + @class.expects(:use_docs).returns true + @class.stubs(:new).with{ |a| a[:doc] == "doc" } + @lexer.expects(:getcomment).with(12).returns "doc" + @parser.ast(@class, :file => "/bar", :line => 12) end end @@ -360,30 +345,28 @@ describe Puppet::Parser do @parser.stubs(:known_resource_types).returns @krt end - it "should create new classes" do - @parser.parse("class foobar {}") - @krt.hostclass("foobar").should be_instance_of(Puppet::Resource::Type) + it "should not create new classes" do + @parser.parse("class foobar {}").code[0].should be_a(Puppet::Parser::AST::Hostclass) + @krt.hostclass("foobar").should be_nil end it "should correctly set the parent class when one is provided" do - @parser.parse("class foobar inherits yayness {}") - @krt.hostclass("foobar").parent.should == "yayness" + @parser.parse("class foobar inherits yayness {}").code[0].instantiate('')[0].parent.should == "yayness" end it "should correctly set the parent class for multiple classes at a time" do - @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}") - @krt.hostclass("foobar").parent.should == "yayness" - @krt.hostclass("boo").parent.should == "bar" + statements = @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}").code + statements[0].instantiate('')[0].parent.should == "yayness" + statements[1].instantiate('')[0].parent.should == "bar" end it "should define the code when some is provided" do - @parser.parse("class foobar { $var = val }") - @krt.hostclass("foobar").code.should_not be_nil + @parser.parse("class foobar { $var = val }").code[0].code.should_not be_nil end it "should define parameters when provided" do - @parser.parse("class foobar($biz,$baz) {}") - @krt.hostclass("foobar").arguments.should == {"biz" => nil, "baz" => nil} + foobar = @parser.parse("class foobar($biz,$baz) {}").code[0].instantiate('')[0] + foobar.arguments.should == {"biz" => nil, "baz" => nil} end end @@ -400,13 +383,37 @@ describe Puppet::Parser do end it "should correctly mark exported resources as exported" do - @parser.parse("@@file { '/file': }") - @krt.hostclass("").code[0].exported.should be_true + @parser.parse("@@file { '/file': }").code[0].exported.should be_true end it "should correctly mark virtual resources as virtual" do - @parser.parse("@file { '/file': }") - @krt.hostclass("").code[0].virtual.should be_true + @parser.parse("@file { '/file': }").code[0].virtual.should be_true + end + end + + describe "when parsing nodes" do + it "should be able to parse a node with a single name" do + node = @parser.parse("node foo { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 1 + node.names[0].value.should == "foo" + end + + it "should be able to parse a node with two names" do + node = @parser.parse("node foo, bar { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 2 + node.names[0].value.should == "foo" + node.names[1].value.should == "bar" + end + + it "should be able to parse a node with three names" do + node = @parser.parse("node foo, bar, baz { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 3 + node.names[0].value.should == "foo" + node.names[1].value.should == "bar" + node.names[2].value.should == "baz" end end end diff --git a/spec/unit/parser/resource_spec.rb b/spec/unit/parser/resource_spec.rb index da49940b0..dae22fcaa 100755 --- a/spec/unit/parser/resource_spec.rb +++ b/spec/unit/parser/resource_spec.rb @@ -58,23 +58,17 @@ describe Puppet::Parser::Resource do end it "should get its environment from its scope" do - scope = stub 'scope', :source => stub("source") - scope.expects(:environment).returns "foo" + scope = stub 'scope', :source => stub("source"), :namespaces => nil + scope.expects(:environment).returns("foo").at_least_once Puppet::Parser::Resource.new("file", "whatever", :scope => scope).environment.should == "foo" end - it "should get its namespaces from its scope" do - scope = stub 'scope', :source => stub("source") - scope.expects(:namespaces).returns %w{one two} - Puppet::Parser::Resource.new("file", "whatever", :scope => scope).namespaces.should == %w{one two} - end - it "should use the resource type collection helper module" do Puppet::Parser::Resource.ancestors.should be_include(Puppet::Resource::TypeCollectionHelper) end it "should use the scope's environment as its environment" do - @scope.expects(:environment).returns "myenv" + @scope.expects(:environment).returns("myenv").at_least_once Puppet::Parser::Resource.new("file", "whatever", :scope => @scope).environment.should == "myenv" end diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 9895f446b..2e390a53b 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -29,8 +29,7 @@ describe Puppet::Parser::Scope do end it "should be able to retrieve its parent module name from the source of its parent type" do - @topscope.source = Puppet::Resource::Type.new(:hostclass, :foo) - @topscope.source.module_name = "foo" + @topscope.source = Puppet::Resource::Type.new(:hostclass, :foo, :module_name => "foo") @scope.parent_module_name.should == "foo" end diff --git a/spec/unit/parser/templatewrapper_spec.rb b/spec/unit/parser/templatewrapper_spec.rb index d4d1d1b8e..68d90a1cc 100755 --- a/spec/unit/parser/templatewrapper_spec.rb +++ b/spec/unit/parser/templatewrapper_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/parser/templatewrapper' describe Puppet::Parser::TemplateWrapper do before(:each) do diff --git a/spec/unit/parser/type_loader_spec.rb b/spec/unit/parser/type_loader_spec.rb index 8f005d551..cfa68871d 100644 --- a/spec/unit/parser/type_loader_spec.rb +++ b/spec/unit/parser/type_loader_spec.rb @@ -28,92 +28,21 @@ describe Puppet::Parser::TypeLoader do describe "when loading names from namespaces" do it "should do nothing if the name to import is an empty string" do @loader.expects(:name2files).never - @loader.load_until(["foo"], "") { |f| false }.should be_nil - end - - it "should turn the provided namespaces and name into a list of files" do - @loader.expects(:name2files).with(["foo"], "bar").returns [] - @loader.load_until(["foo"], "bar") { |f| false } + @loader.try_load_fqname(:hostclass, "") { |filename, modname| raise :should_not_occur }.should be_nil end it "should attempt to import each generated name" do - @loader.expects(:name2files).returns %w{foo bar} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.load_until(["foo"], "bar") { |f| false } - end - - it "should yield after each import" do - yielded = [] - @loader.expects(:name2files).returns %w{foo bar} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.load_until(["foo"], "bar") { |f| yielded << f; false } - yielded.should == %w{foo bar} - end - - it "should stop importing when the yielded block returns true" do - yielded = [] - @loader.expects(:name2files).returns %w{foo bar baz} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.expects(:import).with("baz",nil).never - @loader.load_until(["foo"], "bar") { |f| true if f == "bar" } - end - - it "should return the result of the block" do - yielded = [] - @loader.expects(:name2files).returns %w{foo bar baz} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.expects(:import).with("baz",nil).never - @loader.load_until(["foo"], "bar") { |f| 10 if f == "bar" }.should == 10 - end - - it "should return nil if the block never returns true" do - @loader.expects(:name2files).returns %w{foo bar} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.load_until(["foo"], "bar") { |f| false }.should be_nil - end - - it "should know when a given name has been loaded" do - @loader.expects(:name2files).returns %w{file} - @loader.expects(:import).with("file",nil) - @loader.load_until(["foo"], "bar") { |f| true } - @loader.should be_loaded("file") - end - - it "should set the module name on any created resource types" do - type = Puppet::Resource::Type.new(:hostclass, "mytype") - - Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{one}] - @loader.stubs(:parse_file) - @loader.load_until(["foo"], "one") { |f| type } - - type.module_name.should == "modname" - end - end - - describe "when mapping names to files" do - { - [["foo"], "::bar::baz"] => %w{bar/baz}, - [[""], "foo::bar"] => %w{foo foo/bar}, - [%w{foo}, "bar"] => %w{foo foo/bar bar}, - [%w{a b}, "bar"] => %w{a a/bar b b/bar bar}, - [%w{a::b::c}, "bar"] => %w{a a/b/c/bar bar}, - [%w{a::b}, "foo::bar"] => %w{a a/b/foo/bar foo/bar} - }.each do |inputs, outputs| - it "should produce #{outputs.inspect} from the #{inputs[0].inspect} namespace and #{inputs[1]} name" do - @loader.name2files(*inputs).should == outputs - end + @loader.expects(:import).with("foo/bar",nil).returns([]) + @loader.expects(:import).with("foo",nil).returns([]) + @loader.try_load_fqname(:hostclass, "foo::bar") { |f| false } end end describe "when importing" do before do Puppet::Parser::Files.stubs(:find_manifests).returns ["modname", %w{file}] - @loader.stubs(:parse_file) + Puppet::Parser::Parser.any_instance.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) + Puppet::Parser::Parser.any_instance.stubs(:file=) end it "should return immediately when imports are being ignored" do @@ -144,26 +73,19 @@ describe Puppet::Parser::TypeLoader do it "should parse each found file" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] - @loader.expects(:parse_file).with("/one") + @loader.expects(:parse_file).with("/one").returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile") end it "should make each file qualified before attempting to parse it" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{one}] - @loader.expects(:parse_file).with("/current/one") + @loader.expects(:parse_file).with("/current/one").returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile", "/current/file") end - it "should know when a given file has been imported" do - Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] - @loader.import("myfile") - - @loader.should be_imported("/one") - end - it "should not attempt to import files that have already been imported" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] - @loader.expects(:parse_file).once + Puppet::Parser::Parser.any_instance.expects(:parse).once.returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile") # This will fail if it tries to reimport the file. @@ -174,7 +96,7 @@ describe Puppet::Parser::TypeLoader do describe "when parsing a file" do before do @parser = Puppet::Parser::Parser.new(@loader.environment) - @parser.stubs(:parse) + @parser.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @parser.stubs(:file=) Puppet::Parser::Parser.stubs(:new).with(@loader.environment).returns @parser end @@ -186,16 +108,27 @@ describe Puppet::Parser::TypeLoader do it "should assign the parser its file and parse" do @parser.expects(:file=).with("/my/file") - @parser.expects(:parse) + @parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @loader.parse_file("/my/file") end end it "should be able to add classes to the current resource type collection" do - file = tmpfile("simple_file") + file = tmpfile("simple_file.pp") File.open(file, "w") { |f| f.puts "class foo {}" } @loader.import(file) @loader.known_resource_types.hostclass("foo").should be_instance_of(Puppet::Resource::Type) end + + describe "when deciding where to look for files" do + { 'foo' => ['foo'], + 'foo::bar' => ['foo/bar', 'foo'], + 'foo::bar::baz' => ['foo/bar/baz', 'foo/bar', 'foo'] + }.each do |fqname, expected_paths| + it "should look for #{fqname.inspect} in #{expected_paths.inspect}" do + @loader.instance_eval { name2files(fqname) }.should == expected_paths + end + end + end end diff --git a/spec/unit/provider/confine/exists_spec.rb b/spec/unit/provider/confine/exists_spec.rb index c3958e317..f039208b8 100755 --- a/spec/unit/provider/confine/exists_spec.rb +++ b/spec/unit/provider/confine/exists_spec.rb @@ -39,25 +39,18 @@ describe Puppet::Provider::Confine::Exists do describe "and the confine is for binaries" do before { @confine.stubs(:for_binary).returns true } - it "should use its 'binary' method to look up the full path of the file" do - @confine.expects(:binary).returns nil + it "should use its 'which' method to look up the full path of the file" do + @confine.expects(:which).returns nil @confine.pass?("/my/file") end - it "should return false if no binary can be found" do - @confine.expects(:binary).with("/my/file").returns nil + it "should return false if no executable can be found" do + @confine.expects(:which).with("/my/file").returns nil @confine.pass?("/my/file").should be_false end - it "should return true if the binary can be found and the file exists" do - @confine.expects(:binary).with("/my/file").returns "/my/file" - FileTest.expects(:exist?).with("/my/file").returns true - @confine.pass?("/my/file").should be_true - end - - it "should return false if the binary can be found but the file does not exist" do - @confine.expects(:binary).with("/my/file").returns "/my/file" - FileTest.expects(:exist?).with("/my/file").returns true + it "should return true if the executable can be found" do + @confine.expects(:which).with("/my/file").returns "/my/file" @confine.pass?("/my/file").should be_true end end diff --git a/spec/unit/provider/host/parsed_spec.rb b/spec/unit/provider/host/parsed_spec.rb new file mode 100644 index 000000000..239e3bd86 --- /dev/null +++ b/spec/unit/provider/host/parsed_spec.rb @@ -0,0 +1,196 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet_spec/files' +require 'puppettest/support/utils' +require 'puppettest/fileparsing' + +provider_class = Puppet::Type.type(:host).provider(:parsed) + +describe provider_class do + include PuppetSpec::Files + extend PuppetTest::Support::Utils + include PuppetTest::FileParsing + + before do + @host_class = Puppet::Type.type(:host) + @provider = @host_class.provider(:parsed) + @hostfile = tmpfile('hosts') + @provider.any_instance.stubs(:target).returns @hostfile + end + + after :each do + @provider.initvars + end + + def mkhost(args) + hostresource = Puppet::Type::Host.new(:name => args[:name]) + hostresource.stubs(:should).with(:target).returns @hostfile + + # Using setters of provider + host = @provider.new(hostresource) + args.each do |property,value| + host.send("#{property}=", value) + end + host + end + + def genhost(host) + @provider.stubs(:filetype).returns(Puppet::Util::FileType::FileTypeRam) + File.stubs(:chown) + File.stubs(:chmod) + Puppet::Util::SUIDManager.stubs(:asuser).yields + host.flush + @provider.target_object(@hostfile).read + end + + describe "when parsing a line with ip and hostname" do + + it "should parse an ipv4 from the first field" do + @provider.parse_line("127.0.0.1 localhost")[:ip].should == "127.0.0.1" + end + + it "should parse an ipv6 from the first field" do + @provider.parse_line("::1 localhost")[:ip].should == "::1" + end + + it "should parse the name from the second field" do + @provider.parse_line("::1 localhost")[:name].should == "localhost" + end + + it "should set an empty comment" do + @provider.parse_line("::1 localhost")[:comment].should == "" + end + + end + + describe "when parsing a line with ip, hostname and comment" do + before do + @testline = "127.0.0.1 localhost # A comment with a #-char" + end + + it "should parse the ip from the first field" do + @provider.parse_line(@testline)[:ip].should == "127.0.0.1" + end + + it "should parse the hostname from the second field" do + @provider.parse_line(@testline)[:name].should == "localhost" + end + + it "should parse the comment after the first '#' character" do + @provider.parse_line(@testline)[:comment].should == 'A comment with a #-char' + end + + end + + describe "when parsing a line with ip, hostname and aliases" do + + it "should parse alias from the third field" do + @provider.parse_line("127.0.0.1 localhost localhost.localdomain")[:host_aliases].should == ["localhost.localdomain"] + end + + it "should parse multiple aliases" do + @provider.parse_line("127.0.0.1 host alias1 alias2")[:host_aliases].should == ['alias1', 'alias2'] + @provider.parse_line("127.0.0.1 host alias1\talias2")[:host_aliases].should == ['alias1', 'alias2'] + @provider.parse_line("127.0.0.1 host alias1\talias2 alias3")[:host_aliases].should == ['alias1', 'alias2', 'alias3'] + end + + end + + describe "when parsing a line with ip, hostname, aliases and comment" do + + before do + # Just playing with a few different delimiters + @testline = "127.0.0.1\t host alias1\talias2 alias3 # A comment with a #-char" + end + + it "should parse the ip from the first field" do + @provider.parse_line(@testline)[:ip].should == "127.0.0.1" + end + + it "should parse the hostname from the second field" do + @provider.parse_line(@testline)[:name].should == "host" + end + + it "should parse all host_aliases from the third field" do + @provider.parse_line(@testline)[:host_aliases].should == ['alias1' ,'alias2', 'alias3'] + end + + it "should parse the comment after the first '#' character" do + @provider.parse_line(@testline)[:comment].should == 'A comment with a #-char' + end + + end + + describe "when operating on /etc/hosts like files" do + fakedata("data/providers/host/parsed","valid*").each do |file| + it "should be able to parse #{file}" do + fakedataparse(file) + end + end + + it "should be able to generate a simple hostfile entry" do + host = mkhost( + :name => 'localhost', + :ip => '127.0.0.1', + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost\n" + end + + it "should be able to generate an entry with one alias" do + host = mkhost( + :name => 'localhost.localdomain', + :ip => '127.0.0.1', + :host_aliases => ['localhost'], + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost.localdomain\tlocalhost\n" + end + + it "should be able to generate an entry with more than one alias" do + host = mkhost( + :name => 'host', + :ip => '192.0.0.1', + :host_aliases => [ 'a1','a2','a3','a4' ], + :ensure => :present + ) + genhost(host).should == "192.0.0.1\thost\ta1\ta2\ta3\ta4\n" + end + + it "should be able to generate a simple hostfile entry with comments" do + host = mkhost( + :name => 'localhost', + :ip => '127.0.0.1', + :comment => 'Bazinga!', + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost\t# Bazinga!\n" + end + + it "should be able to generate an entry with one alias and a comment" do + host = mkhost( + :name => 'localhost.localdomain', + :ip => '127.0.0.1', + :host_aliases => ['localhost'], + :comment => 'Bazinga!', + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost.localdomain\tlocalhost\t# Bazinga!\n" + end + + it "should be able to generate an entry with more than one alias and a comment" do + host = mkhost( + :name => 'host', + :ip => '192.0.0.1', + :host_aliases => [ 'a1','a2','a3','a4' ], + :comment => 'Bazinga!', + :ensure => :present + ) + genhost(host).should == "192.0.0.1\thost\ta1\ta2\ta3\ta4\t# Bazinga!\n" + end + + end + +end diff --git a/spec/unit/provider/mount_spec.rb b/spec/unit/provider/mount_spec.rb index 55a52b44a..b034214ee 100755 --- a/spec/unit/provider/mount_spec.rb +++ b/spec/unit/provider/mount_spec.rb @@ -113,7 +113,14 @@ describe Puppet::Provider::Mount do @mounter.should be_mounted end - it "should match ' on <name>' if the operating system is not Darwin or Solaris" do + it "should match '^<name> on' if the operating system is HP-UX" do + Facter.stubs(:value).with("operatingsystem").returns("HP-UX") + @mounter.expects(:mountcmd).returns("/ on /dev/dsk/whatever\n/var on /dev/dsk/other") + + @mounter.should be_mounted + end + + it "should match ' on <name>' if the operating system is not Darwin, Solaris, or HP-UX" do Facter.stubs(:value).with("operatingsystem").returns("Debian") @mounter.expects(:mountcmd).returns("/dev/dsk/whatever on / and stuff\n/dev/other/disk on /var and stuff") diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb new file mode 100644 index 000000000..f6a99aa78 --- /dev/null +++ b/spec/unit/provider/package/yum_spec.rb @@ -0,0 +1,67 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider = Puppet::Type.type(:package).provider(:yum) + +describe provider do + before do + # Create a mock resource + @resource = stub 'resource' + @resource.stubs(:[]).with(:name).returns 'mypackage' + @provider = provider.new(@resource) + @provider.stubs(:resource).returns @resource + @provider.stubs(:yum).returns 'yum' + @provider.stubs(:rpm).returns 'rpm' + @provider.stubs(:get).with(:name).returns 'mypackage' + @provider.stubs(:get).with(:version).returns '1' + @provider.stubs(:get).with(:release).returns '1' + @provider.stubs(:get).with(:arch).returns 'i386' + end + # provider should repond to the following methods + [:install, :latest, :update, :purge].each do |method| + it "should have a(n) #{method}" do + @provider.should respond_to(method) + end + end + + describe 'when installing' do + it 'should call yum install for :installed' do + @resource.stubs(:should).with(:ensure).returns :installed + @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage') + @provider.install + end + it 'should use :install to update' do + @provider.expects(:install) + @provider.update + end + it 'should be able to set version' do + @resource.stubs(:should).with(:ensure).returns '1.2' + @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage-1.2') + @provider.stubs(:query).returns :ensure => '1.2' + @provider.install + end + it 'should be able to downgrade' do + @resource.stubs(:should).with(:ensure).returns '1.0' + @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :downgrade, 'mypackage-1.0') + @provider.stubs(:query).returns(:ensure => '1.2').then.returns(:ensure => '1.0') + @provider.install + end + end + + describe 'when uninstalling' do + it 'should use erase to purge' do + @provider.expects(:yum).with('-y', :erase, 'mypackage') + @provider.purge + end + it 'should use rpm to uninstall' do + @provider.expects(:rpm).with('-e', 'mypackage-1-1.i386') + @provider.uninstall + end + end + + it 'should be versionable' do + provider.should be_versionable + end +end + diff --git a/spec/unit/provider/service/freebsd_spec.rb b/spec/unit/provider/service/freebsd_spec.rb new file mode 100644 index 000000000..0330adbed --- /dev/null +++ b/spec/unit/provider/service/freebsd_spec.rb @@ -0,0 +1,50 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:service).provider(:freebsd) + +describe provider_class do + before :each do + @provider = provider_class.new + @provider.stubs(:initscript) + end + + it "should correctly parse rcvar for FreeBSD < 7" do + @provider.stubs(:execute).returns <<OUTPUT +# ntpd +$ntpd_enable=YES +OUTPUT + @provider.rcvar.should == ['# ntpd', 'ntpd_enable=YES'] + end + + it "should correctly parse rcvar for FreeBSD 7 to 8" do + @provider.stubs(:execute).returns <<OUTPUT +# ntpd +ntpd_enable=YES +OUTPUT + @provider.rcvar.should == ['# ntpd', 'ntpd_enable=YES'] + end + + it "should correctly parse rcvar for FreeBSD >= 8.1" do + @provider.stubs(:execute).returns <<OUTPUT +# ntpd +# +ntpd_enable="YES" +# (default: "") +OUTPUT + @provider.rcvar.should == ['# ntpd', 'ntpd_enable="YES"', '# (default: "")'] + end + + it "should find the right rcvar_value for FreeBSD < 7" do + @provider.stubs(:rcvar).returns(['# ntpd', 'ntpd_enable=YES']) + + @provider.rcvar_value.should == "YES" + end + + it "should find the right rcvar_value for FreeBSD >= 7" do + @provider.stubs(:rcvar).returns(['# ntpd', 'ntpd_enable="YES"', '# (default: "")']) + + @provider.rcvar_value.should == "YES" + end +end diff --git a/spec/unit/provider/service/launchd_spec.rb b/spec/unit/provider/service/launchd_spec.rb index 320ee3ace..43e4cba8e 100755 --- a/spec/unit/provider/service/launchd_spec.rb +++ b/spec/unit/provider/service/launchd_spec.rb @@ -98,19 +98,22 @@ describe provider_class 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}]) - Plist.stubs(:parse_xml).returns({@resource[:name] => {"Disabled" => false}}) + @provider.class.stubs(:read_plist).returns({@resource[:name] => {"Disabled" => false}}) + FileTest.expects(:file?).with(Launchd_Overrides).returns(true) @provider.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}]) - Plist.stubs(:parse_xml).returns({@resource[:name] => {"Disabled" => true}}) + @provider.class.stubs(:read_plist).returns({@resource[:name] => {"Disabled" => true}}) + FileTest.expects(:file?).with(Launchd_Overrides).returns(true) @provider.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", {}]) - Plist.stubs(:parse_xml).returns({}) + @provider.class.stubs(:read_plist).returns({}) + FileTest.expects(:file?).with(Launchd_Overrides).returns(true) @provider.enabled?.should == :true end end @@ -182,7 +185,7 @@ describe provider_class do 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") - Plist.stubs(:parse_xml).returns({}) + @provider.class.stubs(:read_plist).returns({}) Plist::Emit.expects(:save_plist).once @provider.enable end @@ -191,7 +194,7 @@ describe provider_class do 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") - Plist.stubs(:parse_xml).returns({}) + @provider.class.stubs(:read_plist).returns({}) Plist::Emit.expects(:save_plist).once @provider.enable end diff --git a/spec/unit/provider/service/upstart.rb b/spec/unit/provider/service/upstart.rb new file mode 100644 index 000000000..9fde9e67f --- /dev/null +++ b/spec/unit/provider/service/upstart.rb @@ -0,0 +1,49 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:service).provider(:upstart) + +describe provider_class do + describe "#instances" do + it "should be able to find all instances" do + processes = ["rc stop/waiting", "ssh start/running, process 712"] + provider_class.stubs(:execpipe).yields(processes) + provider_class.instances.map {|provider| provider.name}.should =~ ["rc","ssh"] + end + + it "should attach the interface name for network interfaces" do + processes = ["network-interface (eth0)"] + provider_class.stubs(:execpipe).yields(processes) + provider_class.instances.first.name.should == "network-interface INTERFACE=eth0" + end + end + + describe "#status" do + it "should allow the user to override the status command" do + resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart, :status => "/bin/foo") + provider = provider_class.new(resource) + + provider.expects(:ucommand).with { `true`; true } + provider.status.should == :running + end + + it "should use the default status command if none is specified" do + resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart) + provider = provider_class.new(resource) + + provider.expects(:status_exec).with(["foo"]).returns("foo start/running, process 1000") + Process::Status.any_instance.stubs(:exitstatus).returns(0) + provider.status.should == :running + end + + it "should properly handle services with 'start' in their name" do + resource = Puppet::Type.type(:service).new(:name => "foostartbar", :provider => :upstart) + provider = provider_class.new(resource) + + provider.expects(:status_exec).with(["foostartbar"]).returns("foostartbar stop/waiting") + Process::Status.any_instance.stubs(:exitstatus).returns(0) + provider.status.should == :stopped + end + end +end diff --git a/spec/unit/provider/ssh_authorized_key/parsed_spec.rb b/spec/unit/provider/ssh_authorized_key/parsed_spec.rb index 059d010bb..11e9233e0 100755 --- a/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +++ b/spec/unit/provider/ssh_authorized_key/parsed_spec.rb @@ -3,21 +3,22 @@ require File.dirname(__FILE__) + '/../../../spec_helper' require 'puppet_spec/files' -require 'puppettest' require 'puppettest/support/utils' require 'puppettest/fileparsing' +require 'puppettest/fakes' provider_class = Puppet::Type.type(:ssh_authorized_key).provider(:parsed) describe provider_class do include PuppetSpec::Files + extend PuppetTest::Support::Utils include PuppetTest include PuppetTest::FileParsing before :each do @sshauthkey_class = Puppet::Type.type(:ssh_authorized_key) @provider = @sshauthkey_class.provider(:parsed) - @keyfile = File.join(Dir.tmpdir, 'authorized_keys') + @keyfile = tmpfile('authorized_keys') @provider.any_instance.stubs(:target).returns @keyfile @user = 'random_bob' Puppet::Util.stubs(:uid).with(@user).returns 12345 @@ -49,7 +50,7 @@ describe provider_class do @provider.target_object(@keyfile).read end - PuppetTest.fakedata("data/providers/ssh_authorized_key/parsed").each { |file| + fakedata("data/providers/ssh_authorized_key/parsed").each { |file| it "should be able to parse example data in #{file}" do fakedataparse(file) end diff --git a/spec/unit/provider/user/user_role_add_spec.rb b/spec/unit/provider/user/user_role_add_spec.rb index 211f4260a..9cf649267 100644 --- a/spec/unit/provider/user/user_role_add_spec.rb +++ b/spec/unit/provider/user/user_role_add_spec.rb @@ -56,7 +56,7 @@ describe provider_class do 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) + @provider.expects(:run).at_least_once @provider.create end @@ -66,6 +66,15 @@ describe provider_class do @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 @@ -107,6 +116,7 @@ describe provider_class do before do @resource.expects(:allowdupe?).returns true @provider.stubs(:is_role?).returns(false) + @provider.stubs(:execute) @provider.expects(:execute).with { |args| args.include?("-o") } end @@ -246,4 +256,11 @@ describe provider_class do @provider.password=("hashedpassword") 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/provider/user/useradd_spec.rb b/spec/unit/provider/user/useradd_spec.rb index 6eb9717b8..9ebba596c 100755 --- a/spec/unit/provider/user/useradd_spec.rb +++ b/spec/unit/provider/user/useradd_spec.rb @@ -15,6 +15,7 @@ describe provider_class do # #1360 it "should add -o when allowdupe is enabled and the user is being created" do @resource.expects(:allowdupe?).returns true + @provider.stubs(:execute) @provider.expects(:execute).with { |args| args.include?("-o") } @provider.create end @@ -26,6 +27,15 @@ describe provider_class do @provider.uid = 150 end + it "should set password age rules" do + provider_class.has_feature :manages_password_age + @resource = Puppet::Type.type(:user).new :name => "myuser", :password_min_age => 5, :password_max_age => 10, :provider => :useradd + @provider = provider_class.new(@resource) + @provider.stubs(:execute) + @provider.expects(:execute).with { |cmd, *args| args == ["-m", 5, "-M", 10, "myuser"] } + @provider.create + end + describe "when checking to add allow dup" do it "should check allow dup" do @resource.expects(:allowdupe?) @@ -109,7 +119,58 @@ describe provider_class do @provider.stubs(:command).with(:add).returns("useradd") @provider.stubs(:add_properties).returns(["-G", "somegroup"]) @resource.stubs(:[]).with(:name).returns("someuser") + @resource.stubs(:[]).with(:expiry).returns("somedate") + @provider.addcmd.must == ["useradd", "-G", "somegroup", "-o", "-m", '-e somedate', "someuser"] + end + + it "should return an array without -e if expery is undefined full command" do + @provider.stubs(:command).with(:add).returns("useradd") + @provider.stubs(:add_properties).returns(["-G", "somegroup"]) + @resource.stubs(:[]).with(:name).returns("someuser") + @resource.stubs(:[]).with(:expiry).returns nil @provider.addcmd.must == ["useradd", "-G", "somegroup", "-o", "-m", "someuser"] end end + + describe "when calling passcmd" do + before do + @resource.stubs(:allowdupe?).returns true + @resource.stubs(:managehome?).returns true + end + + it "should call command with :pass" do + @provider.expects(:command).with(:password) + @provider.passcmd + end + + it "should return nil if neither min nor max is set" do + @resource.stubs(:should).with(:password_min_age).returns nil + @resource.stubs(:should).with(:password_max_age).returns nil + @provider.passcmd.must == nil + end + + it "should return a chage command array with -m <value> and the user name if password_min_age is set" do + @provider.stubs(:command).with(:password).returns("chage") + @resource.stubs(:[]).with(:name).returns("someuser") + @resource.stubs(:should).with(:password_min_age).returns 123 + @resource.stubs(:should).with(:password_max_age).returns nil + @provider.passcmd.must == ['chage','-m',123,'someuser'] + end + + it "should return a chage command array with -M <value> if password_max_age is set" do + @provider.stubs(:command).with(:password).returns("chage") + @resource.stubs(:[]).with(:name).returns("someuser") + @resource.stubs(:should).with(:password_min_age).returns nil + @resource.stubs(:should).with(:password_max_age).returns 999 + @provider.passcmd.must == ['chage','-M',999,'someuser'] + end + + it "should return a chage command array with -M <value> -m <value> if both password_min_age and password_max_age are set" do + @provider.stubs(:command).with(:password).returns("chage") + @resource.stubs(:[]).with(:name).returns("someuser") + @resource.stubs(:should).with(:password_min_age).returns 123 + @resource.stubs(:should).with(:password_max_age).returns 999 + @provider.passcmd.must == ['chage','-m',123,'-M',999,'someuser'] + end + end end diff --git a/spec/unit/rails/param_value_spec.rb b/spec/unit/rails/param_value_spec.rb index d6dc7d57b..243456e89 100755 --- a/spec/unit/rails/param_value_spec.rb +++ b/spec/unit/rails/param_value_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' describe "Puppet::Rails::ParamValue" do confine "Cannot test without ActiveRecord" => Puppet.features.rails? diff --git a/spec/unit/rails/resource_spec.rb b/spec/unit/rails/resource_spec.rb index 08deda65e..6e23d2020 100755 --- a/spec/unit/rails/resource_spec.rb +++ b/spec/unit/rails/resource_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' describe "Puppet::Rails::Resource" do confine "Cannot test without ActiveRecord" => Puppet.features.rails? @@ -107,7 +108,7 @@ describe "Puppet::Rails::Resource" do describe "#to_resource" do it "should instantiate a Puppet::Parser::Resource" do - scope = stub "scope", :source => nil + scope = stub "scope", :source => nil, :environment => nil, :namespaces => nil @resource = Puppet::Rails::Resource.new @resource.stubs(:attributes).returns({ diff --git a/spec/unit/rails_spec.rb b/spec/unit/rails_spec.rb index eaa968099..24248e622 100755 --- a/spec/unit/rails_spec.rb +++ b/spec/unit/rails_spec.rb @@ -47,14 +47,20 @@ describe Puppet::Rails, "when initializing any connection" do Puppet::Rails.connect end - describe "on ActiveRecord 2.1.x" do - confine("ActiveRecord 2.1.x") { ::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1 } - - it "should set ActiveRecord::Base.allow_concurrency" do + describe "ActiveRecord Version" do + it "should set ActiveRecord::Base.allow_concurrency if ActiveRecord is 2.1" do + Puppet::Util.stubs(:activerecord_version).returns(2.1) ActiveRecord::Base.expects(:allow_concurrency=).with(true) Puppet::Rails.connect end + + it "should not set ActiveRecord::Base.allow_concurrency if ActiveRecord is >= 2.2" do + Puppet::Util.stubs(:activerecord_version).returns(2.2) + ActiveRecord::Base.expects(:allow_concurrency=).never + + Puppet::Rails.connect + end end it "should call ActiveRecord::Base.verify_active_connections!" do @@ -97,9 +103,9 @@ describe Puppet::Rails, "when initializing a mysql connection" do Puppet.settings.stubs(:value).with(:dbport).returns("") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 45).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("") - Puppet.settings.stubs(:value).with(:dbconnections).returns(1) Puppet::Rails.database_arguments.should == { :adapter => "mysql", @@ -107,9 +113,9 @@ describe Puppet::Rails, "when initializing a mysql connection" do :host => "testserver", :username => "testuser", :password => "testpassword", + :pool => pool_size, :database => "testname", - :reconnect => true, - :pool => 1 + :reconnect => true } end @@ -120,9 +126,9 @@ describe Puppet::Rails, "when initializing a mysql connection" do Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 12).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") - Puppet.settings.stubs(:value).with(:dbconnections).returns(1) Puppet::Rails.database_arguments.should == { :adapter => "mysql", @@ -131,10 +137,10 @@ describe Puppet::Rails, "when initializing a mysql connection" do :port => "9999", :username => "testuser", :password => "testpassword", + :pool => pool_size, :database => "testname", :socket => "testsocket", - :reconnect => true, - :pool => 1 + :reconnect => true } end @@ -145,9 +151,9 @@ describe Puppet::Rails, "when initializing a mysql connection" do Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 23).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") - Puppet.settings.stubs(:value).with(:dbconnections).returns(1) Puppet::Rails.database_arguments.should == { :adapter => "mysql", @@ -156,12 +162,32 @@ describe Puppet::Rails, "when initializing a mysql connection" do :port => "9999", :username => "testuser", :password => "testpassword", + :pool => pool_size, :database => "testname", :socket => "testsocket", - :reconnect => true, - :pool => 1 + :reconnect => true } end + + it "should not provide the pool if dbconnections is 0, '0', or ''" do + Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") + Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") + Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") + Puppet.settings.stubs(:value).with(:dbport).returns("9999") + Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") + Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbname).returns("testname") + Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") + + Puppet.settings.stubs(:value).with(:dbconnections).returns(0) + Puppet::Rails.database_arguments.should_not be_include(:pool) + + Puppet.settings.stubs(:value).with(:dbconnections).returns('0') + Puppet::Rails.database_arguments.should_not be_include(:pool) + + Puppet.settings.stubs(:value).with(:dbconnections).returns('') + Puppet::Rails.database_arguments.should_not be_include(:pool) + end end describe Puppet::Rails, "when initializing a postgresql connection" do @@ -174,9 +200,9 @@ describe Puppet::Rails, "when initializing a postgresql connection" do Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 200).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("") - Puppet.settings.stubs(:value).with(:dbconnections).returns(1) Puppet::Rails.database_arguments.should == { :adapter => "postgresql", @@ -185,9 +211,9 @@ describe Puppet::Rails, "when initializing a postgresql connection" do :port => "9999", :username => "testuser", :password => "testpassword", + :pool => pool_size, :database => "testname", - :reconnect => true, - :pool => 1 + :reconnect => true } end @@ -198,9 +224,9 @@ describe Puppet::Rails, "when initializing a postgresql connection" do Puppet.settings.stubs(:value).with(:dbport).returns("9999") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 122).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") - Puppet.settings.stubs(:value).with(:dbconnections).returns(1) Puppet::Rails.database_arguments.should == { :adapter => "postgresql", @@ -209,50 +235,90 @@ describe Puppet::Rails, "when initializing a postgresql connection" do :port => "9999", :username => "testuser", :password => "testpassword", + :pool => pool_size, :database => "testname", :socket => "testsocket", - :pool => 1, :reconnect => true } end + + it "should not provide the pool if dbconnections is 0, '0', or ''" do + Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") + Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") + Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") + Puppet.settings.stubs(:value).with(:dbport).returns("9999") + Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") + Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbname).returns("testname") + Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") + + Puppet.settings.stubs(:value).with(:dbconnections).returns(0) + Puppet::Rails.database_arguments.should_not be_include(:pool) + + Puppet.settings.stubs(:value).with(:dbconnections).returns('0') + Puppet::Rails.database_arguments.should_not be_include(:pool) + + Puppet.settings.stubs(:value).with(:dbconnections).returns('') + Puppet::Rails.database_arguments.should_not be_include(:pool) + end end describe Puppet::Rails, "when initializing an Oracle connection" do confine "Cannot test without ActiveRecord" => Puppet.features.rails? - it "should provide the adapter, log_level, and username, password, dbconnections, and database arguments" do + it "should provide the adapter, log_level, and username, password, and database arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("oracle_enhanced") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 123).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") - Puppet.settings.stubs(:value).with(:dbconnections).returns(1) Puppet::Rails.database_arguments.should == { :adapter => "oracle_enhanced", :log_level => "testlevel", :username => "testuser", :password => "testpassword", - :database => "testname", - :pool => 1 + :pool => pool_size, + :database => "testname" } end - it "should provide the adapter, log_level, and host, username, password, database, pool, and socket arguments" do + it "should provide the adapter, log_level, and host, username, password, database and socket arguments" do Puppet.settings.stubs(:value).with(:dbadapter).returns("oracle_enhanced") Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbconnections).returns((pool_size = 124).to_s) Puppet.settings.stubs(:value).with(:dbname).returns("testname") - Puppet.settings.stubs(:value).with(:dbconnections).returns(1) Puppet::Rails.database_arguments.should == { :adapter => "oracle_enhanced", :log_level => "testlevel", :username => "testuser", :password => "testpassword", - :database => "testname", - :pool => 1 + :pool => pool_size, + :database => "testname" } end + + it "should not provide the pool if dbconnections is 0, '0', or ''" do + Puppet.settings.stubs(:value).with(:dbadapter).returns("mysql") + Puppet.settings.stubs(:value).with(:rails_loglevel).returns("testlevel") + Puppet.settings.stubs(:value).with(:dbserver).returns("testserver") + Puppet.settings.stubs(:value).with(:dbport).returns("9999") + Puppet.settings.stubs(:value).with(:dbuser).returns("testuser") + Puppet.settings.stubs(:value).with(:dbpassword).returns("testpassword") + Puppet.settings.stubs(:value).with(:dbname).returns("testname") + Puppet.settings.stubs(:value).with(:dbsocket).returns("testsocket") + + Puppet.settings.stubs(:value).with(:dbconnections).returns(0) + Puppet::Rails.database_arguments.should_not be_include(:pool) + + Puppet.settings.stubs(:value).with(:dbconnections).returns('0') + Puppet::Rails.database_arguments.should_not be_include(:pool) + + Puppet.settings.stubs(:value).with(:dbconnections).returns('') + Puppet::Rails.database_arguments.should_not be_include(:pool) + end end diff --git a/spec/unit/reports/rrdgraph_spec.rb b/spec/unit/reports/rrdgraph_spec.rb new file mode 100644 index 000000000..ce2cf7905 --- /dev/null +++ b/spec/unit/reports/rrdgraph_spec.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +require 'puppet/reports' + +processor = Puppet::Reports.report(:rrdgraph) + +describe processor do + include PuppetSpec::Files + before do + Puppet[:rrddir] = tmpdir('rrdgraph') + Puppet.settings.use :master + end + + after do + FileUtils.rm_rf(Puppet[:rrddir]) + end + + it "should not error on 0.25.x report format" do + report = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml/report0.25.x.yaml')).extend processor + report.expects(:mkhtml) + lambda{ report.process }.should_not raise_error + end + + it "should not error on 2.6.x report format" do + report = YAML.load_file(File.join(PuppetSpec::FIXTURE_DIR, 'yaml/report2.6.x.yaml')).extend processor + report.expects(:mkhtml) + lambda{ report.process }.should_not raise_error + end +end diff --git a/spec/unit/reports/tagmail_spec.rb b/spec/unit/reports/tagmail_spec.rb index 4349e999d..bdb16600e 100755 --- a/spec/unit/reports/tagmail_spec.rb +++ b/spec/unit/reports/tagmail_spec.rb @@ -3,12 +3,12 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } require 'puppet/reports' -require 'puppettest' +require 'puppettest/support/utils' tagmail = Puppet::Reports.report(:tagmail) describe tagmail do - extend PuppetTest + extend PuppetTest::Support::Utils before do @processor = Puppet::Transaction::Report.new @@ -31,6 +31,7 @@ describe tagmail do { "tag: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag}, []], + "tag.localhost: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag.localhost}, []], "tag, other: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag other}, []], "tag-other: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag-other}, []], "tag, !other: abuse@domain.com" => [%w{abuse@domain.com}, %w{tag}, %w{other}], diff --git a/spec/unit/resource/catalog_spec.rb b/spec/unit/resource/catalog_spec.rb index 10cff91a3..fbfe29ff3 100755 --- a/spec/unit/resource/catalog_spec.rb +++ b/spec/unit/resource/catalog_spec.rb @@ -224,7 +224,7 @@ describe Puppet::Resource::Catalog, "when compiling" do end it "should convert parser resources to plain resources" do - resource = Puppet::Parser::Resource.new(:file, "foo", :scope => stub("scope"), :source => stub("source")) + resource = Puppet::Parser::Resource.new(:file, "foo", :scope => stub("scope", :environment => nil, :namespaces => nil), :source => stub("source")) catalog = Puppet::Resource::Catalog.new("whev") catalog.add_resource(resource) new = catalog.to_resource @@ -374,7 +374,7 @@ describe Puppet::Resource::Catalog, "when compiling" do @original.add_edge(@r1,@r2) @original.filter do |r| r == @r1 - end.edge(@r1,@r2).should be_empty + end.edge?(@r1,@r2).should_not be end end @@ -933,8 +933,8 @@ describe Puppet::Resource::Catalog, "when converting to pson" do @catalog.add_edge(one, two) @catalog.add_edge(two, three) - @catalog.edge(one, two ).expects(:to_pson_data_hash).returns "one_two_pson" - @catalog.edge(two, three).expects(:to_pson_data_hash).returns "two_three_pson" + @catalog.edges_between(one, two )[0].expects(:to_pson_data_hash).returns "one_two_pson" + @catalog.edges_between(two, three)[0].expects(:to_pson_data_hash).returns "two_three_pson" PSON.parse(@catalog.to_pson,:create_additions => false)['data']['edges'].sort.should == %w{one_two_pson two_three_pson}.sort end diff --git a/spec/unit/resource/type_collection_spec.rb b/spec/unit/resource/type_collection_spec.rb index 09643cd24..b8da3cf58 100644 --- a/spec/unit/resource/type_collection_spec.rb +++ b/spec/unit/resource/type_collection_spec.rb @@ -89,6 +89,34 @@ describe Puppet::Resource::TypeCollection do loader.node("node").should be_nil end + describe "when resolving namespaces" do + [ ['', '::foo', ['foo']], + ['a', '::foo', ['foo']], + ['a::b', '::foo', ['foo']], + [['a::b'], '::foo', ['foo']], + [['a::b', 'c'], '::foo', ['foo']], + [['A::B', 'C'], '::Foo', ['foo']], + ['', '', ['']], + ['a', '', ['']], + ['a::b', '', ['']], + [['a::b'], '', ['']], + [['a::b', 'c'], '', ['']], + [['A::B', 'C'], '', ['']], + ['', 'foo', ['foo']], + ['a', 'foo', ['a::foo', 'foo']], + ['a::b', 'foo', ['a::b::foo', 'a::foo', 'foo']], + ['A::B', 'Foo', ['a::b::foo', 'a::foo', 'foo']], + [['a::b'], 'foo', ['a::b::foo', 'a::foo', 'foo']], + [['a', 'b'], 'foo', ['a::foo', 'foo', 'b::foo']], + [['a::b', 'c::d'], 'foo', ['a::b::foo', 'a::foo', 'foo', 'c::d::foo', 'c::foo']], + [['a::b', 'a::c'], 'foo', ['a::b::foo', 'a::foo', 'foo', 'a::c::foo']], + ].each do |namespaces, name, expected_result| + it "should resolve #{name.inspect} in namespaces #{namespaces.inspect} correctly" do + @code.instance_eval { resolve_namespaces(namespaces, name) }.should == expected_result + end + end + end + describe "when looking up names" do before do @type = Puppet::Resource::Type.new(:hostclass, "ns::klass") @@ -107,29 +135,32 @@ describe Puppet::Resource::TypeCollection do describe "that need to be loaded" do it "should use the loader to load the files" do - @code.loader.expects(:load_until).with(["ns"], "klass") - @code.find_or_load(["ns"], "klass", :hostclass) + @code.loader.expects(:try_load_fqname).with(:hostclass, "ns::klass") + @code.loader.expects(:try_load_fqname).with(:hostclass, "klass") + @code.find_hostclass(["ns"], "klass") end it "should downcase the name and downcase and array-fy the namespaces before passing to the loader" do - @code.loader.expects(:load_until).with(["ns"], "klass") - @code.find_or_load("Ns", "Klass", :hostclass) + @code.loader.expects(:try_load_fqname).with(:hostclass, "ns::klass") + @code.loader.expects(:try_load_fqname).with(:hostclass, "klass") + @code.find_hostclass("Ns", "Klass") end - it "should attempt to find the type when the loader yields" do - @code.loader.expects(:load_until).yields - @code.expects(:find).with(["ns"], "klass", :hostclass).times(2).returns(false).then.returns(true) - @code.find_or_load("ns", "klass", :hostclass) + it "should use the class returned by the loader" do + @code.loader.expects(:try_load_fqname).returns(:klass) + @code.expects(:hostclass).with("ns::klass").returns(false) + @code.find_hostclass("ns", "klass").should == :klass end - it "should return the result of 'load_until'" do - @code.loader.expects(:load_until).returns "foo" - @code.find_or_load("Ns", "Klass", :hostclass).should == "foo" + it "should return nil if the name isn't found" do + @code.stubs(:try_load_fqname).returns(nil) + @code.find_hostclass("Ns", "Klass").should be_nil end - it "should return nil if the name isn't found" do - @code.stubs(:load_until).returns(nil) - @code.find_or_load("Ns", "Klass", :hostclass).should be_nil + it "already-loaded names at broader scopes should not shadow autoloaded names" do + @code.add Puppet::Resource::Type.new(:hostclass, "bar") + @code.loader.expects(:try_load_fqname).with(:hostclass, "foo::bar").returns(:foobar) + @code.find_hostclass("foo", "bar").should == :foobar end end end @@ -195,75 +226,102 @@ describe Puppet::Resource::TypeCollection do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance - loader.find("namespace", "::foo::bar", :hostclass).should equal(instance) + loader.find_hostclass("namespace", "::foo::bar").should equal(instance) end it "should return nil if the instance name is fully qualified and no such instance exists" do loader = Puppet::Resource::TypeCollection.new("env") - loader.find("namespace", "::foo::bar", :hostclass).should be_nil + loader.find_hostclass("namespace", "::foo::bar").should be_nil end it "should be able to find classes in the base namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo") loader.add instance - loader.find("", "foo", :hostclass).should equal(instance) + loader.find_hostclass("", "foo").should equal(instance) end it "should return the partially qualified object if it exists in a provided namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo", "bar::baz", :hostclass).should equal(instance) + loader.find_hostclass("foo", "bar::baz").should equal(instance) end it "should be able to find partially qualified objects in any of the provided namespaces" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find(["nons", "foo", "otherns"], "bar::baz", :hostclass).should equal(instance) + loader.find_hostclass(["nons", "foo", "otherns"], "bar::baz").should equal(instance) end it "should return the unqualified object if it exists in a provided namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance - loader.find("foo", "bar", :hostclass).should equal(instance) + loader.find_hostclass("foo", "bar").should equal(instance) end it "should return the unqualified object if it exists in the parent namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance - loader.find("foo::bar::baz", "bar", :hostclass).should equal(instance) + loader.find_hostclass("foo::bar::baz", "bar").should equal(instance) end it "should should return the partially qualified object if it exists in the parent namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo::bar", "bar::baz", :hostclass).should equal(instance) + loader.find_hostclass("foo::bar", "bar::baz").should equal(instance) end it "should return the qualified object if it exists in the root namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo::bar", "foo::bar::baz", :hostclass).should equal(instance) + loader.find_hostclass("foo::bar", "foo::bar::baz").should equal(instance) end it "should return nil if the object cannot be found" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo::bar", "eh", :hostclass).should be_nil + loader.find_hostclass("foo::bar", "eh").should be_nil end + + describe "when topscope has a class that has the same name as a local class" do + before do + @loader = Puppet::Resource::TypeCollection.new("env") + [ "foo::bar", "bar" ].each do |name| + @loader.add Puppet::Resource::Type.new(:hostclass, name) + end + end + + it "should favor the local class, if the name is unqualified" do + @loader.find_hostclass("foo", "bar").name.should == 'foo::bar' + end + + it "should only look in the topclass, if the name is qualified" do + @loader.find_hostclass("foo", "::bar").name.should == 'bar' + end + + end + + it "should not look in the local scope for classes when the name is qualified" do + @loader = Puppet::Resource::TypeCollection.new("env") + @loader.add Puppet::Resource::Type.new(:hostclass, "foo::bar") + + @loader.find_hostclass("foo", "::bar").should == nil + end + end - it "should use the generic 'find' method with an empty namespace to find nodes" do + it "should be able to find nodes" do + node = Puppet::Resource::Type.new(:node, "bar") loader = Puppet::Resource::TypeCollection.new("env") - loader.expects(:find).with("", "bar", :node) - loader.find_node(stub("ignored"), "bar") + loader.add(node) + loader.find_node(stub("ignored"), "bar").should == node end it "should use the 'find_or_load' method to find hostclasses" do @@ -358,50 +416,6 @@ describe Puppet::Resource::TypeCollection do end end - describe "when performing initial import" do - before do - @parser = stub 'parser', :file= => nil, :string => nil, :parse => nil - Puppet::Parser::Parser.stubs(:new).returns @parser - @code = Puppet::Resource::TypeCollection.new("env") - end - - it "should create a new parser instance" do - Puppet::Parser::Parser.expects(:new).returns @parser - @code.perform_initial_import - end - - it "should set the parser's string to the 'code' setting and parse if code is available" do - Puppet.settings[:code] = "my code" - @parser.expects(:string=).with "my code" - @parser.expects(:parse) - @code.perform_initial_import - end - - it "should set the parser's file to the 'manifest' setting and parse if no code is available and the manifest is available" do - File.stubs(:expand_path).with("/my/file").returns "/my/file" - File.expects(:exist?).with("/my/file").returns true - Puppet.settings[:manifest] = "/my/file" - @parser.expects(:file=).with "/my/file" - @parser.expects(:parse) - @code.perform_initial_import - end - - it "should not attempt to load a manifest if none is present" do - File.stubs(:expand_path).with("/my/file").returns "/my/file" - File.expects(:exist?).with("/my/file").returns false - Puppet.settings[:manifest] = "/my/file" - @parser.expects(:file=).never - @parser.expects(:parse).never - @code.perform_initial_import - end - - it "should fail helpfully if there is an error importing" do - File.stubs(:exist?).returns true - @parser.expects(:parse).raises ArgumentError - lambda { @code.perform_initial_import }.should raise_error(Puppet::Error) - end - end - describe "when determining the configuration version" do before do @code = Puppet::Resource::TypeCollection.new("env") @@ -429,4 +443,5 @@ describe Puppet::Resource::TypeCollection do end end + end diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 0ef4a5166..ef45712e6 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -322,7 +322,7 @@ describe Puppet::Resource::Type do end it "should set its module name in the scope if available" do - @type.module_name = "mymod" + @type.instance_eval { @module_name = "mymod" } @type.set_resource_parameters(@resource, @scope) @@ -369,7 +369,8 @@ describe Puppet::Resource::Type do end it "should cache a reference to the parent type" do - @code.expects(:hostclass).once.with("bar").returns @parent + @code.stubs(:hostclass).with("foo::bar").returns nil + @code.expects(:hostclass).with("bar").once.returns @parent @child.parent_type(@scope) @child.parent_type end @@ -411,6 +412,23 @@ describe Puppet::Resource::Type do @type = Puppet::Resource::Type.new(:hostclass, "foo") end + it "should add hostclass names to the classes list" do + @type.evaluate_code(@resource) + @compiler.catalog.classes.should be_include("foo") + end + + it "should add node names to the classes list" do + @type = Puppet::Resource::Type.new(:node, "foo") + @type.evaluate_code(@resource) + @compiler.catalog.classes.should be_include("foo") + end + + it "should not add defined resource names to the classes list" do + @type = Puppet::Resource::Type.new(:definition, "foo") + @type.evaluate_code(@resource) + @compiler.catalog.classes.should_not be_include("foo") + end + it "should set all of its parameters in a subscope" do subscope = stub 'subscope', :compiler => @compiler @type.expects(:subscope).with(@scope, @resource).returns subscope @@ -513,8 +531,7 @@ describe Puppet::Resource::Type do @compiler.add_resource @scope, @parent_resource @type.resource_type_collection = @scope.known_resource_types - @type.resource_type_collection.stubs(:node).with("parent").returns(@parent_type) - @type.resource_type_collection.stubs(:node).with("Parent").returns(@parent_type) + @type.resource_type_collection.add(@parent_type) end it "should evaluate the parent's resource" do @@ -562,29 +579,29 @@ describe Puppet::Resource::Type do end it "should create a resource instance" do - @top.mk_plain_resource(@scope).should be_instance_of(Puppet::Parser::Resource) + @top.ensure_in_catalog(@scope).should be_instance_of(Puppet::Parser::Resource) end it "should set its resource type to 'class' when it is a hostclass" do - Puppet::Resource::Type.new(:hostclass, "top").mk_plain_resource(@scope).type.should == "Class" + Puppet::Resource::Type.new(:hostclass, "top").ensure_in_catalog(@scope).type.should == "Class" end it "should set its resource type to 'node' when it is a node" do - Puppet::Resource::Type.new(:node, "top").mk_plain_resource(@scope).type.should == "Node" + Puppet::Resource::Type.new(:node, "top").ensure_in_catalog(@scope).type.should == "Node" end it "should fail when it is a definition" do - lambda { Puppet::Resource::Type.new(:definition, "top").mk_plain_resource(@scope) }.should raise_error(ArgumentError) + lambda { Puppet::Resource::Type.new(:definition, "top").ensure_in_catalog(@scope) }.should raise_error(ArgumentError) end it "should add the created resource to the scope's catalog" do - @top.mk_plain_resource(@scope) + @top.ensure_in_catalog(@scope) @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end it "should evaluate the parent class if one exists" do - @middle.mk_plain_resource(@scope) + @middle.ensure_in_catalog(@scope) @compiler.catalog.resource(:class, "top").should be_instance_of(Puppet::Parser::Resource) end @@ -592,40 +609,40 @@ describe Puppet::Resource::Type do it "should fail to evaluate if a parent class is defined but cannot be found" do othertop = Puppet::Resource::Type.new :hostclass, "something", :parent => "yay" @code.add othertop - lambda { othertop.mk_plain_resource(@scope) }.should raise_error(Puppet::ParseError) + lambda { othertop.ensure_in_catalog(@scope) }.should raise_error(Puppet::ParseError) end it "should not create a new resource if one already exists" do @compiler.catalog.expects(:resource).with(:class, "top").returns("something") @compiler.catalog.expects(:add_resource).never - @top.mk_plain_resource(@scope) + @top.ensure_in_catalog(@scope) end it "should return the existing resource when not creating a new one" do @compiler.catalog.expects(:resource).with(:class, "top").returns("something") @compiler.catalog.expects(:add_resource).never - @top.mk_plain_resource(@scope).should == "something" + @top.ensure_in_catalog(@scope).should == "something" end it "should not create a new parent resource if one already exists and it has a parent class" do - @top.mk_plain_resource(@scope) + @top.ensure_in_catalog(@scope) top_resource = @compiler.catalog.resource(:class, "top") - @middle.mk_plain_resource(@scope) + @middle.ensure_in_catalog(@scope) @compiler.catalog.resource(:class, "top").should equal(top_resource) end # #795 - tag before evaluation. it "should tag the catalog with the resource tags when it is evaluated" do - @middle.mk_plain_resource(@scope) + @middle.ensure_in_catalog(@scope) @compiler.catalog.should be_tagged("middle") end it "should tag the catalog with the parent class tags when it is evaluated" do - @middle.mk_plain_resource(@scope) + @middle.ensure_in_catalog(@scope) @compiler.catalog.should be_tagged("top") end diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 204a2b02e..e65e8a13a 100755 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -123,18 +123,6 @@ describe Puppet::Resource do Puppet::Resource.new("file", "/my/file", :environment => :foo).environment.name.should == :foo end - it "should support specifying namespaces" do - Puppet::Resource.new("file", "/my/file", :namespaces => ["foo"]).namespaces.should == ["foo"] - end - - it "should convert namespaces to an array if not specified as one" do - Puppet::Resource.new("file", "/my/file", :namespaces => "foo").namespaces.should == ["foo"] - end - - it "should default to a single amespace of an empty string" do - Puppet::Resource.new("file", "/my/file").namespaces.should == [""] - end - describe "and munging its type and title" do describe "when modeling a builtin resource" do it "should be able to find the resource type" do @@ -164,16 +152,6 @@ describe Puppet::Resource do it "should set its title to the provided title" do Puppet::Resource.new("foo::bar", "/my/file").title.should == "/my/file" end - - describe "and the resource is unqualified and models a qualified resource type" do - it "should set its type to the fully qualified resource type" do - Puppet::Resource.new("bar", "/my/file", :namespaces => %w{foo}).type.should == "Foo::Bar" - end - - it "should be able to find the resource type" do - Puppet::Resource.new("bar", "/my/file", :namespaces => %w{foo}).resource_type.should equal(@type) - end - end end describe "that does not exist" do @@ -210,20 +188,6 @@ describe Puppet::Resource do it "should be able to find the resource type" do Puppet::Resource.new("class", "foo::bar").resource_type.should equal(@type) end - - describe "and the resource is unqualified and models a qualified class" do - it "should set its title to the fully qualified resource type" do - Puppet::Resource.new("class", "bar", :namespaces => %w{foo}).title.should == "Foo::Bar" - end - - it "should be able to find the resource type" do - Puppet::Resource.new("class", "bar", :namespaces => %w{foo}).resource_type.should equal(@type) - end - - it "should set its type to 'Class'" do - Puppet::Resource.new("class", "bar", :namespaces => %w{foo}).type.should == "Class" - end - end end describe "that does not exist" do diff --git a/spec/unit/simple_graph_spec.rb b/spec/unit/simple_graph_spec.rb index 83e674139..fa0bcb06a 100755 --- a/spec/unit/simple_graph_spec.rb +++ b/spec/unit/simple_graph_spec.rb @@ -31,12 +31,6 @@ describe Puppet::SimpleGraph do proc { @graph.to_dot_graph }.should_not raise_error end - it "should always put its edges first when printing yaml" do - @graph = Puppet::SimpleGraph.new - @graph.add_edge(:one, :two) - @graph.to_yaml_properties[0].should == "@edges" - end - describe "when managing vertices" do before do @graph = Puppet::SimpleGraph.new @@ -117,16 +111,31 @@ describe Puppet::SimpleGraph do @graph.edge?(:one, :two).should be_true end - it "should provide a method for retrieving an edge label" do - edge = Puppet::Relationship.new(:one, :two, :callback => :awesome) - @graph.add_edge(edge) - @graph.edge_label(:one, :two).should == {:callback => :awesome} - end + describe "when retrieving edges between two nodes" do + it "should handle the case of nodes not in the graph" do + @graph.edges_between(:one, :two).should == [] + end - it "should provide a method for retrieving an edge" do - edge = Puppet::Relationship.new(:one, :two) - @graph.add_edge(edge) - @graph.edge(:one, :two).should equal(edge) + it "should handle the case of nodes with no edges between them" do + @graph.add_vertex(:one) + @graph.add_vertex(:two) + @graph.edges_between(:one, :two).should == [] + end + + it "should handle the case of nodes connected by a single edge" do + edge = Puppet::Relationship.new(:one, :two) + @graph.add_edge(edge) + @graph.edges_between(:one, :two).length.should == 1 + @graph.edges_between(:one, :two)[0].should equal(edge) + end + + it "should handle the case of nodes connected by multiple edges" do + edge1 = Puppet::Relationship.new(:one, :two, :callback => :foo) + edge2 = Puppet::Relationship.new(:one, :two, :callback => :bar) + @graph.add_edge(edge1) + @graph.add_edge(edge2) + Set.new(@graph.edges_between(:one, :two)).should == Set.new([edge1, edge2]) + end end it "should add the edge source as a vertex if it is not already" do @@ -253,7 +262,7 @@ describe Puppet::SimpleGraph do it "should retain labels on edges" do @graph.add_edge(:one, :two, :callback => :awesome) - edge = @graph.reversal.edge(:two, :one) + edge = @graph.reversal.edges_between(:two, :one)[0] edge.label.should == {:callback => :awesome} end end @@ -439,7 +448,8 @@ describe Puppet::SimpleGraph do @middle = Container.new("middle", ["e", "f", @two]) @top = Container.new("top", ["g", "h", @middle, @one, @three]) @empty = Container.new("empty", []) - + + @whit = Puppet::Type.type(:whit) @stage = Puppet::Type.type(:stage).new(:name => "foo") @contgraph = @top.to_graph @@ -499,8 +509,17 @@ describe Puppet::SimpleGraph do end end + it "should contain a whit-resource to mark the place held by the empty container" do + @depgraph.vertices.find_all { |v| v.is_a?(@whit) }.length.should == 1 + end + + it "should replace edges to empty containers with edges to their residual whit" do + emptys_whit = @depgraph.vertices.find_all { |v| v.is_a?(@whit) }.first + @depgraph.should be_edge("c", emptys_whit) + end + it "should no longer contain anything but the non-container objects" do - @depgraph.vertices.find_all { |v| ! v.is_a?(String) }.should be_empty + @depgraph.vertices.find_all { |v| ! v.is_a?(String) and ! v.is_a?(@whit)}.should be_empty end it "should copy labels" do @@ -512,14 +531,14 @@ describe Puppet::SimpleGraph do it "should not add labels to edges that have none" do @depgraph.add_edge(@two, @three) splice - @depgraph.edge_label("c", "i").should == {} + @depgraph.edges_between("c", "i")[0].label.should == {} end it "should copy labels over edges that have none" do @depgraph.add_edge("c", @three, {:callback => :refresh}) splice # And make sure the label got copied. - @depgraph.edge_label("c", "i").should == {:callback => :refresh} + @depgraph.edges_between("c", "i")[0].label.should == {:callback => :refresh} end it "should not replace a label with a nil label" do @@ -527,7 +546,7 @@ describe Puppet::SimpleGraph do @depgraph.add_edge(@middle, @three) @depgraph.add_edge("c", @three, {:callback => :refresh}) splice - @depgraph.edge_label("c", "i").should == {:callback => :refresh} + @depgraph.edges_between("c", "i")[0].label.should == {:callback => :refresh} end it "should copy labels to all created edges" do @@ -537,8 +556,207 @@ describe Puppet::SimpleGraph do @three.each do |child| edge = Puppet::Relationship.new("c", child) @depgraph.should be_edge(edge.source, edge.target) - @depgraph.edge_label(edge.source, edge.target).should == {:callback => :refresh} + @depgraph.edges_between(edge.source, edge.target)[0].label.should == {:callback => :refresh} + end + end + end + + it "should serialize to YAML using the old format by default" do + Puppet::SimpleGraph.use_new_yaml_format.should == false + end + + describe "(yaml tests)" do + def empty_graph(graph) + end + + def one_vertex_graph(graph) + graph.add_vertex(:a) + end + + def graph_without_edges(graph) + [:a, :b, :c].each { |x| graph.add_vertex(x) } + end + + def one_edge_graph(graph) + graph.add_edge(:a, :b) + end + + def many_edge_graph(graph) + graph.add_edge(:a, :b) + graph.add_edge(:a, :c) + graph.add_edge(:b, :d) + graph.add_edge(:c, :d) + end + + def labeled_edge_graph(graph) + graph.add_edge(:a, :b, :callback => :foo, :event => :bar) + end + + def overlapping_edge_graph(graph) + graph.add_edge(:a, :b, :callback => :foo, :event => :bar) + graph.add_edge(:a, :b, :callback => :biz, :event => :baz) + end + + def self.all_test_graphs + [:empty_graph, :one_vertex_graph, :graph_without_edges, :one_edge_graph, :many_edge_graph, :labeled_edge_graph, + :overlapping_edge_graph] + end + + def object_ids(enumerable) + # Return a sorted list of the object id's of the elements of an + # enumerable. + enumerable.collect { |x| x.object_id }.sort + end + + def graph_to_yaml(graph, which_format) + previous_use_new_yaml_format = Puppet::SimpleGraph.use_new_yaml_format + Puppet::SimpleGraph.use_new_yaml_format = (which_format == :new) + ZAML.dump(graph) + ensure + Puppet::SimpleGraph.use_new_yaml_format = previous_use_new_yaml_format + end + + # Test serialization of graph to YAML. + [:old, :new].each do |which_format| + all_test_graphs.each do |graph_to_test| + it "should be able to serialize #{graph_to_test} to YAML (#{which_format} format)" do + graph = Puppet::SimpleGraph.new + send(graph_to_test, graph) + yaml_form = graph_to_yaml(graph, which_format) + + # Hack the YAML so that objects in the Puppet namespace get + # changed to YAML::DomainType objects. This lets us inspect + # the serialized objects easily without invoking any + # yaml_initialize hooks. + yaml_form.gsub!('!ruby/object:Puppet::', '!hack/object:Puppet::') + serialized_object = YAML.load(yaml_form) + + # Check that the object contains instance variables @edges and + # @vertices only. @reversal is also permitted, but we don't + # check it, because it is going to be phased out. + serialized_object.type_id.should == 'object:Puppet::SimpleGraph' + serialized_object.value.keys.reject { |x| x == 'reversal' }.sort.should == ['edges', 'vertices'] + + # Check edges by forming a set of tuples (source, target, + # callback, event) based on the graph and the YAML and make sure + # they match. + edges = serialized_object.value['edges'] + edges.should be_a(Array) + expected_edge_tuples = graph.edges.collect { |edge| [edge.source, edge.target, edge.callback, edge.event] } + actual_edge_tuples = edges.collect do |edge| + edge.type_id.should == 'object:Puppet::Relationship' + %w{source target}.each { |x| edge.value.keys.should include(x) } + edge.value.keys.each { |x| ['source', 'target', 'callback', 'event'].should include(x) } + %w{source target callback event}.collect { |x| edge.value[x] } + end + Set.new(actual_edge_tuples).should == Set.new(expected_edge_tuples) + actual_edge_tuples.length.should == expected_edge_tuples.length + + # Check vertices one by one. + vertices = serialized_object.value['vertices'] + if which_format == :old + vertices.should be_a(Hash) + Set.new(vertices.keys).should == Set.new(graph.vertices) + vertices.each do |key, value| + value.type_id.should == 'object:Puppet::SimpleGraph::VertexWrapper' + value.value.keys.sort.should == %w{adjacencies vertex} + value.value['vertex'].should equal(key) + adjacencies = value.value['adjacencies'] + adjacencies.should be_a(Hash) + Set.new(adjacencies.keys).should == Set.new([:in, :out]) + [:in, :out].each do |direction| + adjacencies[direction].should be_a(Hash) + expected_adjacent_vertices = Set.new(graph.adjacent(key, :direction => direction, :type => :vertices)) + Set.new(adjacencies[direction].keys).should == expected_adjacent_vertices + adjacencies[direction].each do |adj_key, adj_value| + # Since we already checked edges, just check consistency + # with edges. + desired_source = direction == :in ? adj_key : key + desired_target = direction == :in ? key : adj_key + expected_edges = edges.select do |edge| + edge.value['source'] == desired_source && edge.value['target'] == desired_target + end + adj_value.should be_a(Set) + if object_ids(adj_value) != object_ids(expected_edges) + raise "For vertex #{key.inspect}, direction #{direction.inspect}: expected adjacencies #{expected_edges.inspect} but got #{adj_value.inspect}" + end + end + end + end + else + vertices.should be_a(Array) + Set.new(vertices).should == Set.new(graph.vertices) + vertices.length.should == graph.vertices.length + end + end + end + + # Test deserialization of graph from YAML. This presumes the + # correctness of serialization to YAML, which has already been + # tested. + all_test_graphs.each do |graph_to_test| + it "should be able to deserialize #{graph_to_test} from YAML (#{which_format} format)" do + reference_graph = Puppet::SimpleGraph.new + send(graph_to_test, reference_graph) + yaml_form = graph_to_yaml(reference_graph, which_format) + recovered_graph = YAML.load(yaml_form) + + # Test that the recovered vertices match the vertices in the + # reference graph. + expected_vertices = reference_graph.vertices.to_a + recovered_vertices = recovered_graph.vertices.to_a + Set.new(recovered_vertices).should == Set.new(expected_vertices) + recovered_vertices.length.should == expected_vertices.length + + # Test that the recovered edges match the edges in the + # reference graph. + expected_edge_tuples = reference_graph.edges.collect do |edge| + [edge.source, edge.target, edge.callback, edge.event] + end + recovered_edge_tuples = recovered_graph.edges.collect do |edge| + [edge.source, edge.target, edge.callback, edge.event] + end + Set.new(recovered_edge_tuples).should == Set.new(expected_edge_tuples) + recovered_edge_tuples.length.should == expected_edge_tuples.length + + # We ought to test that the recovered graph is self-consistent + # too. But we're not going to bother with that yet because + # the internal representation of the graph is about to change. + end + end + + it "should be able to serialize a graph where the vertices contain backreferences to the graph (#{which_format} format)" do + reference_graph = Puppet::SimpleGraph.new + vertex = Object.new + vertex.instance_eval { @graph = reference_graph } + reference_graph.add_edge(vertex, :other_vertex) + yaml_form = graph_to_yaml(reference_graph, which_format) + recovered_graph = YAML.load(yaml_form) + + recovered_graph.vertices.length.should == 2 + recovered_vertex = recovered_graph.vertices.reject { |x| x.is_a?(Symbol) }[0] + recovered_vertex.instance_eval { @graph }.should equal(recovered_graph) + recovered_graph.edges.length.should == 1 + recovered_edge = recovered_graph.edges[0] + recovered_edge.source.should equal(recovered_vertex) + recovered_edge.target.should == :other_vertex + end + end + + it "should serialize properly when used as a base class" do + class Puppet::TestDerivedClass < Puppet::SimpleGraph + attr_accessor :foo end + derived = Puppet::TestDerivedClass.new + derived.add_edge(:a, :b) + derived.foo = 1234 + recovered_derived = YAML.load(YAML.dump(derived)) + recovered_derived.class.should equal(Puppet::TestDerivedClass) + recovered_derived.edges.length.should == 1 + recovered_derived.edges[0].source.should == :a + recovered_derived.edges[0].target.should == :b + recovered_derived.vertices.length.should == 2 + recovered_derived.foo.should == 1234 end end end diff --git a/spec/unit/sslcertificates/ca_spec.rb b/spec/unit/sslcertificates/ca_spec.rb new file mode 100644 index 000000000..b1393b25d --- /dev/null +++ b/spec/unit/sslcertificates/ca_spec.rb @@ -0,0 +1,110 @@ +#!/usr/bin/env ruby +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet' +require 'puppet/sslcertificates' +require 'puppet/sslcertificates/ca' + +describe Puppet::SSLCertificates::CA do + before :all do + @hosts = %w{host.domain.com Other.Testing.Com} + end + + before :each do + Puppet::Util::SUIDManager.stubs(:asuser).yields + file = Tempfile.new("ca_testing") + @dir = file.path + file.delete + + Puppet.settings[:confdir] = @dir + Puppet.settings[:vardir] = @dir + + @ca = Puppet::SSLCertificates::CA.new + end + + after :each do + system("rm -rf #{@dir}") + 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/transaction/report_spec.rb b/spec/unit/transaction/report_spec.rb index 7e0b0554b..b310713d2 100755 --- a/spec/unit/transaction/report_spec.rb +++ b/spec/unit/transaction/report_spec.rb @@ -225,8 +225,19 @@ describe Puppet::Transaction::Report do @report.calculate_metrics end - %w{Changes Total Resources}.each do |main| - it "should include information on #{main} in the summary" do + %w{changes time resources events}.each do |main| + it "should include the key #{main} in the raw summary hash" do + @report.raw_summary.should be_key main + end + end + + it "should include the last run time in the raw summary hash" do + Time.stubs(:now).returns(Time.utc(2010,11,10,12,0,24)) + @report.raw_summary["time"]["last_run"].should == 1289390424 + end + + %w{Changes Total Resources Time Events}.each do |main| + it "should include information on #{main} in the textual summary" do @report.summary.should be_include(main) end end diff --git a/spec/unit/transaction/resource_harness_spec.rb b/spec/unit/transaction/resource_harness_spec.rb index 31965c92c..255481ae4 100755 --- a/spec/unit/transaction/resource_harness_spec.rb +++ b/spec/unit/transaction/resource_harness_spec.rb @@ -50,7 +50,7 @@ describe Puppet::Transaction::ResourceHarness do end it "should cache and log the current value if no cached values are present" do - @resource.expects(:info) + @resource.expects(:debug) @harness.copy_audited_parameters(@resource, {:mode => "755"}).should == [] @harness.cached(@resource, :mode).should == "755" diff --git a/spec/unit/type/file/content_spec.rb b/spec/unit/type/file/content_spec.rb index e4b9f9bc6..cde643fc8 100755 --- a/spec/unit/type/file/content_spec.rb +++ b/spec/unit/type/file/content_spec.rb @@ -6,6 +6,7 @@ content = Puppet::Type.type(:file).attrclass(:content) describe content do before do @resource = Puppet::Type.type(:file).new :path => "/foo/bar" + content.stubs(:standalone?).returns(false) end it "should be a subclass of Property" do @@ -362,7 +363,7 @@ describe content do end it "should send the correct indirection uri" do - @conn.expects(:request_get).with { |uri,headers| uri == "/production/file_content//path/to/source" }.yields(@response) + @conn.expects(:request_get).with { |uri,headers| uri == "/production/file_content/path/to/source" }.yields(@response) @content.write(@fh) end diff --git a/spec/unit/type/host_spec.rb b/spec/unit/type/host_spec.rb new file mode 100755 index 000000000..12ae2af08 --- /dev/null +++ b/spec/unit/type/host_spec.rb @@ -0,0 +1,83 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +ssh_authorized_key = Puppet::Type.type(:ssh_authorized_key) + +describe Puppet::Type.type(:host) do + before do + @class = Puppet::Type.type(:host) + @catalog = Puppet::Resource::Catalog.new + end + + it "should have :name be its namevar" do + @class.key_attributes.should == [:name] + end + + describe "when validating attributes" do + [:name, :provider ].each do |param| + it "should have a #{param} parameter" do + @class.attrtype(param).should == :param + end + end + + [:ip, :target, :host_aliases, :comment, :ensure].each do |property| + it "should have a #{property} property" do + @class.attrtype(property).should == :property + end + end + end + + describe "when validating values" do + it "should support present as a value for ensure" do + proc { @class.new(:name => "foo", :ensure => :present) }.should_not raise_error + end + + it "should support absent as a value for ensure" do + proc { @class.new(:name => "foo", :ensure => :absent) }.should_not raise_error + end + + it "should accept IPv4 addresses" do + proc { @class.new(:name => "foo", :ip => '10.96.0.1') }.should_not raise_error + end + + it "should accept long IPv6 addresses" do + # Taken from wikipedia article about ipv6 + proc { @class.new(:name => "foo", :ip => '2001:0db8:85a3:08d3:1319:8a2e:0370:7344') }.should_not raise_error + end + + it "should accept one host_alias" do + proc { @class.new(:name => "foo", :host_aliases => 'alias1') }.should_not raise_error + end + + it "should accept multiple host_aliases" do + proc { @class.new(:name => "foo", :host_aliases => [ 'alias1', 'alias2' ]) }.should_not raise_error + end + + it "should accept shortened IPv6 addresses" do + proc { @class.new(:name => "foo", :ip => '2001:db8:0:8d3:0:8a2e:70:7344') }.should_not raise_error + proc { @class.new(:name => "foo", :ip => '::ffff:192.0.2.128') }.should_not raise_error + proc { @class.new(:name => "foo", :ip => '::1') }.should_not raise_error + end + + it "should not accept malformed IPv4 addresses like 192.168.0.300" do + proc { @class.new(:name => "foo", :ip => '192.168.0.300') }.should raise_error + end + + it "should not accept malformed IP addresses like 2001:0dg8:85a3:08d3:1319:8a2e:0370:7344" do + proc { @class.new(:name => "foo", :ip => '2001:0dg8:85a3:08d3:1319:8a2e:0370:7344') }.should raise_error + end + + it "should not accept spaces in resourcename" do + proc { @class.new(:name => "foo bar") }.should raise_error + end + + it "should not accept host_aliases with spaces" do + proc { @class.new(:name => "foo", :host_aliases => [ 'well_formed', 'not wellformed' ]) }.should raise_error + end + + it "should not accept empty host_aliases" do + proc { @class.new(:name => "foo", :host_aliases => ['alias1','']) }.should raise_error + end + end +end diff --git a/spec/unit/type/mount_spec.rb b/spec/unit/type/mount_spec.rb index ce82cb516..4aa9baf70 100755 --- a/spec/unit/type/mount_spec.rb +++ b/spec/unit/type/mount_spec.rb @@ -203,23 +203,45 @@ describe Puppet::Type.type(:mount)::Ensure do end end - describe Puppet::Type.type(:mount), "when responding to events" do + describe Puppet::Type.type(:mount), "when responding to refresh" do - it "should remount if it is currently mounted" do - @provider.expects(:mounted?).returns(true) + it "should remount if it is supposed to be mounted" do + @mount[:ensure] = "mounted" @provider.expects(:remount) @mount.refresh end - it "should not remount if it is not currently mounted" do - @provider.expects(:mounted?).returns(false) + it "should not remount if it is supposed to be present" do + @mount[:ensure] = "present" + @provider.expects(:remount).never + + @mount.refresh + end + + it "should not remount if it is supposed to be absent" do + @mount[:ensure] = "absent" + @provider.expects(:remount).never + + @mount.refresh + end + + it "should not remount if it is supposed to be defined" do + @mount[:ensure] = "defined" + @provider.expects(:remount).never + + @mount.refresh + end + + it "should not remount if it is supposed to be unmounted" do + @mount[:ensure] = "unmounted" @provider.expects(:remount).never @mount.refresh end it "should not remount swap filesystems" do + @mount[:ensure] = "mounted" @mount[:fstype] = "swap" @provider.expects(:remount).never diff --git a/spec/unit/type/schedule_spec.rb b/spec/unit/type/schedule_spec.rb index 6975529b2..8305431a6 100755 --- a/spec/unit/type/schedule_spec.rb +++ b/spec/unit/type/schedule_spec.rb @@ -13,14 +13,6 @@ module ScheduleTesting Time.at(diff) end - def month(method, count) - diff(:hour, 3600 * 24 * 30, method, count) - end - - def week(method, count) - diff(:hour, 3600 * 24 * 7, method, count) - end - def day(method, count) diff(:hour, 3600 * 24, method, count) end @@ -33,15 +25,11 @@ module ScheduleTesting diff(:min, 60, method, count) end - def sec(method, count) - diff(:sec, 1, method, count) - end - end describe Puppet::Type.type(:schedule) do before :each do - Puppet.settings.stubs(:value).with(:ignoreschedules).returns(false) + Puppet[:ignoreschedules] = false @schedule = Puppet::Type.type(:schedule).new(:name => "testing") end @@ -194,26 +182,18 @@ describe Puppet::Type.type(:schedule) do end it "should match if the times are one minute apart and the current minute is 0" do - current = Time.now + current = Time.utc(2008, 1, 1, 0, 0, 0) + previous = Time.utc(2007, 12, 31, 23, 59, 0) - # Subtract an hour, reset the minute to zero, then add 59 minutes, so we're the previous hour plus 59 minutes. - previous = (current - 3600 - (current.min * 60) + (59 * 60)) - - # Now set the "current" time to the zero minute of the current hour. - now = (current - (current.min * 60)) - Time.stubs(:now).returns(now) + Time.stubs(:now).returns(current) @schedule.match?(previous).should be_true end - it "should not match if the times are 58 minutes apart and the current minute is 59" do - current = Time.now + it "should not match if the times are 59 minutes apart and the current minute is 59" do + current = Time.utc(2009, 2, 1, 12, 59, 0) + previous = Time.utc(2009, 2, 1, 12, 0, 0) - # reset the minute to zero - previous = current - (current.min * 60) - - # Now set the "current" time to the 59th minute of the current hour. - now = (current - (current.min * 60) + (59 * 60)) - Time.stubs(:now).returns(now) + Time.stubs(:now).returns(current) @schedule.match?(previous).should be_false end end @@ -227,10 +207,7 @@ describe Puppet::Type.type(:schedule) do end it "should match if the times are one minute apart and the current minute and hour are 0" do - zero = Time.now - - # Reset the current time to X:00:00 - current = zero - (zero.hour * 3600) - (zero.min * 60) - zero.sec + current = Time.utc(2010, "nov", 7, 0, 0, 0) # Now set the previous time to one minute before that previous = current - 60 @@ -240,10 +217,9 @@ describe Puppet::Type.type(:schedule) do end it "should not match if the times are 23 hours and 58 minutes apart and the current hour is 23 and the current minute is 59" do - zero = Time.now # Reset the previous time to 00:00:00 - previous = zero - (zero.hour * 3600) - (zero.min * 60) - zero.sec + previous = Time.utc(2010, "nov", 7, 0, 0, 0) # Set the current time to 23:59 now = previous + (23 * 3600) + (59 * 60) @@ -262,19 +238,17 @@ describe Puppet::Type.type(:schedule) do end it "should match if the previous time is prior to the most recent Sunday" do - now = Time.now - - # Subtract the number days we've progressed into the week, plus one because we're zero-indexed. - previous = now - (3600 * 24 * (now.wday + 1)) + now = Time.utc(2010, "nov", 11, 0, 0, 0) # Thursday + Time.stubs(:now).returns(now) + previous = Time.utc(2010, "nov", 6, 23, 59, 59) # Sat @schedule.match?(previous).should be_true end it "should not match if the previous time is after the most recent Saturday" do - now = Time.now - - # Subtract the number days we've progressed into the week - previous = now - (3600 * 24 * now.wday) + now = Time.utc(2010, "nov", 11, 0, 0, 0) # Thursday + Time.stubs(:now).returns(now) + previous = Time.utc(2010, "nov", 7, 0, 0, 0) # Sunday @schedule.match?(previous).should be_false end @@ -289,19 +263,17 @@ describe Puppet::Type.type(:schedule) do end it "should match when the previous time is prior to the first day of this month" do - now = Time.now - - # Subtract the number days we've progressed into the month - previous = now - (3600 * 24 * now.day) + now = Time.utc(2010, "nov", 8, 00, 59, 59) + Time.stubs(:now).returns(now) + previous = Time.utc(2010, "oct", 31, 23, 59, 59) @schedule.match?(previous).should be_true end it "should not match when the previous time is after the last day of last month" do - now = Time.now - - # Subtract the number days we've progressed into the month, minus one - previous = now - (3600 * 24 * (now.day - 1)) + now = Time.utc(2010, "nov", 8, 00, 59, 59) + Time.stubs(:now).returns(now) + previous = Time.utc(2010, "nov", 1, 0, 0, 0) @schedule.match?(previous).should be_false end diff --git a/spec/unit/type/service_spec.rb b/spec/unit/type/service_spec.rb index 0f4a50750..77628670a 100755 --- a/spec/unit/type/service_spec.rb +++ b/spec/unit/type/service_spec.rb @@ -66,6 +66,10 @@ describe Puppet::Type.type(:service), "when validating attribute values" do Puppet::Type.type(:service).new(:name => "yay", :hasstatus => :false) end + it "should specify :true as the default value of hasstatus" do + Puppet::Type.type(:service).new(:name => "yay")[:hasstatus].should == :true + end + it "should support :true as a value to :hasrestart" do Puppet::Type.type(:service).new(:name => "yay", :hasrestart => :true) end @@ -76,10 +80,18 @@ describe Puppet::Type.type(:service), "when validating attribute values" do it "should allow setting the :enable parameter if the provider has the :enableable feature" do Puppet::Type.type(:service).defaultprovider.stubs(:supports_parameter?).returns(true) + Puppet::Type.type(:service).defaultprovider.expects(:supports_parameter?).with(Puppet::Type.type(:service).attrclass(:enable)).returns(true) svc = Puppet::Type.type(:service).new(:name => "yay", :enable => true) svc.should(:enable).should == :true end + it "should not allow setting the :enable parameter if the provider is missing the :enableable feature" do + Puppet::Type.type(:service).defaultprovider.stubs(:supports_parameter?).returns(true) + Puppet::Type.type(:service).defaultprovider.expects(:supports_parameter?).with(Puppet::Type.type(:service).attrclass(:enable)).returns(false) + svc = Puppet::Type.type(:service).new(:name => "yay", :enable => true) + svc.should(:enable).should be_nil + end + it "should split paths on ':'" do FileTest.stubs(:exist?).returns(true) FileTest.stubs(:directory?).returns(true) diff --git a/spec/unit/type/tidy_spec.rb b/spec/unit/type/tidy_spec.rb index 11edbfbf3..1573ead1b 100755 --- a/spec/unit/type/tidy_spec.rb +++ b/spec/unit/type/tidy_spec.rb @@ -110,7 +110,8 @@ describe tidy do :b => 0, :kb => 1, :mb => 2, - :gb => 3 + :gb => 3, + :tb => 4 } convertors.each do |unit, multiple| diff --git a/spec/unit/type/user_spec.rb b/spec/unit/type/user_spec.rb index abe18933f..ccea9ee4c 100755 --- a/spec/unit/type/user_spec.rb +++ b/spec/unit/type/user_spec.rb @@ -35,6 +35,14 @@ describe user do user.provider_feature(:manages_solaris_rbac).should_not be_nil end + it "should have a manages_expiry feature" do + user.provider_feature(:manages_expiry).should_not be_nil + end + + it "should have a manages_password_age feature" do + user.provider_feature(:manages_password_age).should_not be_nil + end + describe "instances" do it "should have a valid provider" do user.new(:name => "foo").provider.class.ancestors.should be_include(Puppet::Provider) @@ -47,7 +55,7 @@ describe user do end end - properties = [:ensure, :uid, :gid, :home, :comment, :shell, :password, :groups, :roles, :auths, :profiles, :project, :keys] + properties = [:ensure, :uid, :gid, :home, :comment, :shell, :password, :password_min_age, :password_max_age, :groups, :roles, :auths, :profiles, :project, :keys, :expiry] properties.each do |property| it "should have a #{property} property" do @@ -227,6 +235,16 @@ describe user do end end + describe "when managing expiry" do + before do + @expiry = user.attrclass(:expiry).new(:resource => @resource) + end + + it "should fail if given an invalid date" do + lambda { @expiry.should = "200-20-20" }.should raise_error(Puppet::Error) + end + end + describe "when managing passwords" do before do @password = user.attrclass(:password).new(:resource => @resource, :should => "mypass") @@ -262,6 +280,11 @@ describe user do end describe "when user has roles" do + before do + # To test this feature, we have to support it. + user.new(:name => "foo").provider.class.stubs(:feature?).returns(true) + end + it "should autorequire roles" do testuser = Puppet::Type.type(:user).new(:name => "testuser") testuser[:roles] = "testrole" diff --git a/spec/unit/type/whit_spec.rb b/spec/unit/type/whit_spec.rb new file mode 100644 index 000000000..998d9df30 --- /dev/null +++ b/spec/unit/type/whit_spec.rb @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +whit = Puppet::Type.type(:whit).new(:name => "Foo::Bar") + +describe whit do + it "should stringify as though it were the class it represents" do + whit.to_s.should == "Class[Foo::Bar]" + end +end diff --git a/spec/unit/type_spec.rb b/spec/unit/type_spec.rb index 487750e52..48b00ec4a 100755 --- a/spec/unit/type_spec.rb +++ b/spec/unit/type_spec.rb @@ -545,6 +545,13 @@ describe Puppet::Type.metaparamclass(:audit) do @resource[:audit].should == list end + it "should accept the string 'all' to specify auditing all possible properties" do + @resource[:audit] = 'all' + + list = @resource.class.properties.collect { |p| p.name } + @resource[:audit].should == list + end + it "should fail if asked to audit an invalid property" do lambda { @resource[:audit] = :foobar }.should raise_error(Puppet::Error) end diff --git a/spec/unit/util/backups_spec.rb b/spec/unit/util/backups_spec.rb index 5c10d4c3c..259b18652 100755 --- a/spec/unit/util/backups_spec.rb +++ b/spec/unit/util/backups_spec.rb @@ -3,7 +3,6 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/util/backups' -include PuppetTest describe Puppet::Util::Backups do before do diff --git a/spec/unit/util/command_line_spec.rb b/spec/unit/util/command_line_spec.rb index a83ad968d..7ba965249 100644 --- a/spec/unit/util/command_line_spec.rb +++ b/spec/unit/util/command_line_spec.rb @@ -86,7 +86,7 @@ describe Puppet::Util::CommandLine do describe "when the subcommand is not implemented" do it "should find and invoke an executable with a hyphenated name" do commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument'], @tty) - Puppet::Util.expects(:binary).with('puppet-whatever').returns('/dev/null/puppet-whatever') + Puppet::Util.expects(:which).with('puppet-whatever').returns('/dev/null/puppet-whatever') commandline.expects(:system).with('/dev/null/puppet-whatever', 'argument') commandline.execute @@ -95,7 +95,7 @@ describe Puppet::Util::CommandLine do describe "and an external implementation cannot be found" do it "should abort and show the usage message" do commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument'], @tty) - Puppet::Util.expects(:binary).with('puppet-whatever').returns(nil) + Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) commandline.expects(:system).never commandline.expects(:usage_message).returns("the usage message") diff --git a/spec/unit/util/file_locking_spec.rb b/spec/unit/util/file_locking_spec.rb index 10051060c..8fafb1d52 100755 --- a/spec/unit/util/file_locking_spec.rb +++ b/spec/unit/util/file_locking_spec.rb @@ -32,17 +32,12 @@ describe Puppet::Util::FileLocking do end it "should use a global shared mutex" do - @sync = mock 'sync' - @sync.expects(:synchronize).with(Sync::SH).once - Puppet::Util.expects(:sync).with('/file').returns @sync - + Puppet::Util.expects(:synchronize_on).with('/file',Sync::SH).once Puppet::Util::FileLocking.readlock '/file' end it "should use a shared lock on the file" do - @sync = mock 'sync' - @sync.stubs(:synchronize).yields - Puppet::Util.expects(:sync).with('/file').returns @sync + Puppet::Util.expects(:synchronize_on).with('/file',Sync::SH).yields fh = mock 'filehandle' File.expects(:open).with("/file").yields fh @@ -59,9 +54,7 @@ describe Puppet::Util::FileLocking do end it "should create missing files" do - @sync = mock 'sync' - @sync.stubs(:synchronize).yields - Puppet::Util.expects(:sync).with('/file').returns @sync + Puppet::Util.expects(:synchronize_on).with('/file',Sync::SH).yields File.expects(:exists?).with('/file').returns false File.expects(:open).with('/file').once @@ -72,9 +65,7 @@ describe Puppet::Util::FileLocking do describe "when acquiring a write lock" do before do - @sync = mock 'sync' - Puppet::Util.stubs(:sync).returns @sync - @sync.stubs(:synchronize).yields + Puppet::Util.stubs(:synchronize_on).yields File.stubs(:file?).with('/file').returns true File.stubs(:exists?).with('/file').returns true end @@ -88,29 +79,26 @@ describe Puppet::Util::FileLocking do end it "should use a global exclusive mutex" do - sync = mock 'sync' - sync.expects(:synchronize).with(Sync::EX) - Puppet::Util.expects(:sync).with("/file").returns sync - + Puppet::Util.expects(:synchronize_on).with("/file",Sync::EX) Puppet::Util::FileLocking.writelock '/file' end it "should use any specified mode when opening the file" do - File.expects(:open).with("/file", "w", :mymode) + File.expects(:open).with("/file", File::Constants::CREAT | File::Constants::WRONLY , :mymode) Puppet::Util::FileLocking.writelock('/file', :mymode) end it "should use the mode of the existing file if no mode is specified" do File.expects(:stat).with("/file").returns(mock("stat", :mode => 0755)) - File.expects(:open).with("/file", "w", 0755) + File.expects(:open).with("/file", File::Constants::CREAT | File::Constants::WRONLY, 0755) Puppet::Util::FileLocking.writelock('/file') end it "should use 0600 as the mode if no mode is specified and the file does not exist" do File.expects(:stat).raises(Errno::ENOENT) - File.expects(:open).with("/file", "w", 0600) + File.expects(:open).with("/file", File::Constants::CREAT | File::Constants::WRONLY, 0600) Puppet::Util::FileLocking.writelock('/file') end @@ -130,6 +118,8 @@ describe Puppet::Util::FileLocking do lfh = mock 'locked_filehandle' fh.expects(:lock_exclusive).yields(lfh) + lfh.stubs(:seek) + lfh.stubs(:truncate) lfh.expects(:print).with "foo" Puppet::Util::FileLocking.writelock('/file') do |f| @@ -137,18 +127,32 @@ describe Puppet::Util::FileLocking do end end + it "should truncate the file under an exclusive lock" do + fh = mock 'fh' + File.expects(:open).yields fh + + lfh = mock 'locked_filehandle' + fh.expects(:lock_exclusive).yields(lfh) + + lfh.expects(:seek).with(0, IO::SEEK_SET) + lfh.expects(:truncate).with(0) + lfh.stubs(:print) + + Puppet::Util::FileLocking.writelock('/file') do |f| + f.print "foo" + end + end + it "should only work on regular files" do File.expects(:file?).with('/file').returns false proc { Puppet::Util::FileLocking.writelock('/file') }.should raise_error(ArgumentError) end it "should create missing files" do - @sync = mock 'sync' - @sync.stubs(:synchronize).yields - Puppet::Util.expects(:sync).with('/file').returns @sync + Puppet::Util.expects(:synchronize_on).with('/file',Sync::EX).yields File.expects(:exists?).with('/file').returns false - File.expects(:open).with('/file', 'w', 0600).once + File.expects(:open).with('/file', File::Constants::CREAT | File::Constants::WRONLY, 0600).once Puppet::Util::FileLocking.writelock('/file') end diff --git a/spec/unit/util/json_spec.rb b/spec/unit/util/json_spec.rb deleted file mode 100755 index 4f6cea997..000000000 --- a/spec/unit/util/json_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/util/pson' - -class PsonUtil - include Puppet::Util::Pson -end - -describe Puppet::Util::Pson do - it "should fail if no data is provided" do - lambda { PsonUtil.new.pson_create("type" => "foo") }.should raise_error(ArgumentError) - end - - it "should call 'from_pson' with the provided data" do - pson = PsonUtil.new - pson.expects(:from_pson).with("mydata") - pson.pson_create("type" => "foo", "data" => "mydata") - end -end diff --git a/spec/unit/util/log_spec.rb b/spec/unit/util/log_spec.rb index 7d96fe190..ea5d59859 100755 --- a/spec/unit/util/log_spec.rb +++ b/spec/unit/util/log_spec.rb @@ -7,7 +7,7 @@ require 'puppet/util/log' describe Puppet::Util::Log do it "should write a given message to the specified destination" do arraydest = [] - Puppet::Util::Log.newdestination(arraydest) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(arraydest)) Puppet::Util::Log.new(:level => :notice, :message => "foo") message = arraydest.last.message message.should == "foo" @@ -87,7 +87,7 @@ describe Puppet::Util::Log do it "should flush the log queue when the first destination is specified" do Puppet::Util::Log.close_all Puppet::Util::Log.expects(:flushqueue) - Puppet::Util::Log.newdestination([]) + Puppet::Util::Log.newdestination(:console) end it "should convert the level to a symbol if it's passed in as a string" do diff --git a/spec/unit/util/monkey_patches_spec.rb b/spec/unit/util/monkey_patches_spec.rb index b0f61c808..049ed1044 100644 --- a/spec/unit/util/monkey_patches_spec.rb +++ b/spec/unit/util/monkey_patches_spec.rb @@ -5,3 +5,29 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f require 'puppet/util/monkey_patches' + +describe "yaml deserialization" do + it "should call yaml_initialize when deserializing objects that have that method defined" do + class Puppet::TestYamlInitializeClass + attr_reader :foo + + def yaml_initialize(tag, var) + var.should == {'foo' => 100} + instance_variables.should == [] + @foo = 200 + end + end + + obj = YAML.load("--- !ruby/object:Puppet::TestYamlInitializeClass\n foo: 100") + obj.foo.should == 200 + end + + it "should not call yaml_initialize if not defined" do + class Puppet::TestYamlNonInitializeClass + attr_reader :foo + end + + obj = YAML.load("--- !ruby/object:Puppet::TestYamlNonInitializeClass\n foo: 100") + obj.foo.should == 100 + end +end diff --git a/spec/unit/util/pson_spec.rb b/spec/unit/util/pson_spec.rb new file mode 100755 index 000000000..474ddafa4 --- /dev/null +++ b/spec/unit/util/pson_spec.rb @@ -0,0 +1,53 @@ +#!/usr/bin/env ruby + +Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } + +require 'puppet/util/pson' + +class PsonUtil + include Puppet::Util::Pson +end + +describe Puppet::Util::Pson do + it "should fail if no data is provided" do + lambda { PsonUtil.new.pson_create("type" => "foo") }.should raise_error(ArgumentError) + end + + it "should call 'from_pson' with the provided data" do + pson = PsonUtil.new + pson.expects(:from_pson).with("mydata") + pson.pson_create("type" => "foo", "data" => "mydata") + end + + + { + 'foo' => '"foo"', + 1 => '1', + "\x80" => "\"\x80\"", + [] => '[]' + }.each { |str,pson| + it "should be able to encode #{str.inspect}" do + str.to_pson.should == pson + end + } + + it "should be able to handle arbitrary binary data" do + bin_string = (1..20000).collect { |i| ((17*i+13*i*i) % 255).chr }.join + PSON.parse(%Q{{ "type": "foo", "data": #{bin_string.to_pson} }})["data"].should == bin_string + end + + it "should be able to handle UTF8 that isn't a real unicode character" do + s = ["\355\274\267"] + PSON.parse( [s].to_pson ).should == [s] + end + + it "should be able to handle UTF8 for \\xFF" do + s = ["\xc3\xbf"] + PSON.parse( [s].to_pson ).should == [s] + end + + it "should be able to handle invalid UTF8 bytes" do + s = ["\xc3\xc3"] + PSON.parse( [s].to_pson ).should == [s] + end +end diff --git a/spec/unit/util/rdoc/parser_spec.rb b/spec/unit/util/rdoc/parser_spec.rb index a9c8190a6..04713f293 100755 --- a/spec/unit/util/rdoc/parser_spec.rb +++ b/spec/unit/util/rdoc/parser_spec.rb @@ -19,8 +19,8 @@ describe RDoc::Parser do it "should parse puppet files with the puppet parser" do @parser.stubs(:scan_top_level) parser = stub 'parser' - Puppet::Parser::Parser.expects(:new).returns(parser) - parser.expects(:parse) + Puppet::Parser::Parser.stubs(:new).returns(parser) + parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) parser.expects(:file=).with("module/manifests/init.pp") @parser.scan @@ -29,6 +29,7 @@ describe RDoc::Parser do it "should scan the ast for Puppet files" do parser = stub_everything 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) + parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @parser.expects(:scan_top_level) @@ -38,6 +39,7 @@ describe RDoc::Parser do it "should return a PuppetTopLevel to RDoc" do parser = stub_everything 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) + parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @parser.expects(:scan_top_level) @@ -47,8 +49,8 @@ describe RDoc::Parser do describe "when scanning top level entities" do before :each do - @resource_type_collection = stub_everything 'resource_type_collection' - @parser.ast = @resource_type_collection + @resource_type_collection = resource_type_collection = stub_everything('resource_type_collection') + @parser.instance_eval { @known_resource_types = resource_type_collection } @parser.stubs(:split_module).returns("module") @topcontainer = stub_everything 'topcontainer' @@ -85,8 +87,8 @@ describe RDoc::Parser do @parser.scan_top_level(@topcontainer) end - it "should set the module as global if we parse the global manifests (ie <site> module)" do - @parser.stubs(:split_module).returns("<site>") + it "should set the module as global if we parse the global manifests (ie __site__ module)" do + @parser.stubs(:split_module).returns(RDoc::Parser::SITE) @parser.stubs(:parse_elements) @topcontainer.expects(:global=).with(true) @@ -131,7 +133,7 @@ describe RDoc::Parser do it "should return <site> for manifests not under module path" do File.stubs(:expand_path).returns("/path/to/manifests/init.pp") File.stubs(:identical?).returns(false) - @parser.split_module("/path/to/manifests/init.pp").should == "<site>" + @parser.split_module("/path/to/manifests/init.pp").should == RDoc::Parser::SITE end end @@ -141,8 +143,8 @@ describe RDoc::Parser do @definition = stub_everything 'definition', :file => "module/manifests/init.pp", :type => :definition, :name => "mydef" @node = stub_everything 'node', :file => "module/manifests/init.pp", :type => :node, :name => "mynode" - @resource_type_collection = Puppet::Resource::TypeCollection.new("env") - @parser.ast = @resource_type_collection + @resource_type_collection = resource_type_collection = Puppet::Resource::TypeCollection.new("env") + @parser.instance_eval { @known_resource_types = resource_type_collection } @container = stub_everything 'container' end @@ -340,10 +342,12 @@ describe RDoc::Parser do def create_stmt(name) stmt_value = stub "#{name}_value", :value => "myclass" - stmt = stub_everything 'stmt', :name => name, :arguments => [stmt_value], :doc => "mydoc" - stmt.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(false) - stmt.stubs(:is_a?).with(Puppet::Parser::AST::Function).returns(true) - stmt + + Puppet::Parser::AST::Function.new( + :name => name, + :arguments => [stmt_value], + :doc => 'mydoc' + ) end before(:each) do @@ -377,10 +381,11 @@ describe RDoc::Parser do def create_stmt stmt_value = stub "resource_ref", :to_s => "File[\"/tmp/a\"]" - stmt = stub_everything 'stmt', :name => "realize", :arguments => [stmt_value], :doc => "mydoc" - stmt.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(false) - stmt.stubs(:is_a?).with(Puppet::Parser::AST::Function).returns(true) - stmt + Puppet::Parser::AST::Function.new( + :name => 'realize', + :arguments => [stmt_value], + :doc => 'mydoc' + ) end before(:each) do @@ -432,11 +437,16 @@ describe RDoc::Parser do describe "when scanning for resources" do before :each do @class = stub_everything 'class' - - param = stub 'params', :children => [] - @stmt = stub_everything 'stmt', :type => "File", :title => "myfile", :doc => "mydoc", :params => param - @stmt.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(false) - @stmt.stubs(:is_a?).with(Puppet::Parser::AST::Resource).returns(true) + @stmt = Puppet::Parser::AST::Resource.new( + :type => "File", + :instances => Puppet::Parser::AST::ASTArray.new(:children => [ + Puppet::Parser::AST::ResourceInstance.new( + :title => Puppet::Parser::AST::Name.new(:value => "myfile"), + :parameters => Puppet::Parser::AST::ASTArray.new(:children => []) + ) + ]), + :doc => 'mydoc' + ) @code = stub_everything 'code' @code.stubs(:is_a?).with(Puppet::Parser::AST::ASTArray).returns(true) diff --git a/spec/unit/util/rdoc_spec.rb b/spec/unit/util/rdoc_spec.rb index 65df26156..41d4b9cd0 100755 --- a/spec/unit/util/rdoc_spec.rb +++ b/spec/unit/util/rdoc_spec.rb @@ -43,12 +43,20 @@ describe Puppet::Util::RDoc do Puppet::Util::RDoc.rdoc("output", [], "utf-8") end - it "should tell RDoc to force updates of indices" do + it "should tell RDoc to force updates of indices when RDoc supports it" do + Options::OptionList.stubs(:options).returns([["--force-update", "-U", 0 ]]) @rdoc.expects(:document).with { |args| args.include?("--force-update") } Puppet::Util::RDoc.rdoc("output", []) end + it "should not tell RDoc to force updates of indices when RDoc doesn't support it" do + Options::OptionList.stubs(:options).returns([]) + @rdoc.expects(:document).never.with { |args| args.include?("--force-update") } + + Puppet::Util::RDoc.rdoc("output", []) + end + it "should tell RDoc to use the given outputdir" do @rdoc.expects(:document).with { |args| args.include?("--op") and args.include?("myoutputdir") } @@ -75,6 +83,19 @@ describe Puppet::Util::RDoc do Puppet::Util::RDoc.manifestdoc([]) end + it "should use a parser with the correct environment" do + FileTest.stubs(:file?).returns(true) + Puppet::Util::RDoc.stubs(:output) + + parser = stub_everything + Puppet::Parser::Parser.stubs(:new).with{ |env| env.is_a?(Puppet::Node::Environment) }.returns(parser) + + parser.expects(:file=).with("file") + parser.expects(:parse) + + Puppet::Util::RDoc.manifestdoc(["file"]) + end + it "should puppet parse all given files" do FileTest.stubs(:file?).returns(true) Puppet::Util::RDoc.stubs(:output) diff --git a/spec/unit/util/storage_spec.rb b/spec/unit/util/storage_spec.rb index 6c8baba1f..ae3cbc2ae 100755 --- a/spec/unit/util/storage_spec.rb +++ b/spec/unit/util/storage_spec.rb @@ -3,15 +3,14 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'yaml' -require 'tempfile' - require 'puppet/util/storage' describe Puppet::Util::Storage do + include PuppetSpec::Files before(:all) do @basepath = Puppet.features.posix? ? "/somepath" : "C:/somepath" - Puppet[:statedir] = Dir.tmpdir + Puppet[:statedir] = tmpdir("statedir") end after(:all) do diff --git a/spec/unit/util/zaml_spec.rb b/spec/unit/util/zaml_spec.rb index 4de57e6d3..358c6aa11 100644..100755 --- a/spec/unit/util/zaml_spec.rb +++ b/spec/unit/util/zaml_spec.rb @@ -11,7 +11,8 @@ describe "Pure ruby yaml implementation" do 'test' => "--- test", [] => "--- []", :symbol => "--- !ruby/sym symbol", - {:a => "A"} => "--- \n !ruby/sym a: A" + {:a => "A"} => "--- \n !ruby/sym a: A", + {:a => "x\ny"} => "--- \n !ruby/sym a: |-\n x\n y" }.each { |o,y| it "should convert the #{o.class} #{o.inspect} to yaml" do o.to_yaml.should == y @@ -34,5 +35,29 @@ describe "Pure ruby yaml implementation" do lambda { YAML.load(o.to_yaml) }.should_not raise_error end } -end + it "should emit proper labels and backreferences for common objects" do + # Note: this test makes assumptions about the names ZAML chooses + # for labels. + x = [1, 2] + y = [3, 4] + z = [x, y, x, y] + z.to_yaml.should == "--- \n - &id001\n - 1\n - 2\n - &id002\n - 3\n - 4\n - *id001\n - *id002" + z2 = YAML.load(z.to_yaml) + z2.should == z + z2[0].should equal(z2[2]) + z2[1].should equal(z2[3]) + end + + it "should emit proper labels and backreferences for recursive objects" do + x = [1, 2] + x << x + x.to_yaml.should == "--- &id001\n \n - 1\n - 2\n - *id001" + x2 = YAML.load(x.to_yaml) + x2.should be_a(Array) + x2.length.should == 3 + x2[0].should == 1 + x2[1].should == 2 + x2[2].should equal(x2) + end +end diff --git a/tasks/rake/git_workflow.rake b/tasks/rake/git_workflow.rake index b2f96c603..4c39f98de 100644 --- a/tasks/rake/git_workflow.rake +++ b/tasks/rake/git_workflow.rake @@ -103,10 +103,21 @@ task :mail_patches do # Create all of the patches sh "git format-patch -C -M -s -n --subject-prefix='PATCH/puppet' #{parent}..HEAD" + # Add info to the patches + additional_info = "Local-branch: #{branch}\n" + files = Dir.glob("00*.patch") + files.each do |file| + contents = File.read(file) + contents.sub!(/^---\n/, "---\n#{additional_info}") + File.open(file, 'w') do |file_handle| + file_handle.print contents + end + end + # And then mail them out. # If we've got more than one patch, add --compose - if Dir.glob("00*.patch").length > 1 + if files.length > 1 compose = "--compose" else compose = "" diff --git a/tasks/rake/tracdocs.rake b/tasks/rake/tracdocs.rake deleted file mode 100644 index d26d8fc17..000000000 --- a/tasks/rake/tracdocs.rake +++ /dev/null @@ -1,8 +0,0 @@ -task :tracdocs do - require 'puppet' - require 'puppet/util/reference' - Puppet::Util::Reference.references.each do |ref| - sh "puppetdoc -m trac -r #{ref.to_s}" - end -end - diff --git a/test/certmgr/ca.rb b/test/certmgr/ca.rb deleted file mode 100755 index 7e0498dfb..000000000 --- a/test/certmgr/ca.rb +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../lib/puppettest' - -require 'puppet' -require 'puppet/sslcertificates/ca.rb' -require 'puppettest' -require 'puppettest/certificates' -require 'mocha' - -class TestCA < Test::Unit::TestCase - include PuppetTest - - def setup - super - Puppet::Util::SUIDManager.stubs(:asuser).yields - end - - def hosts - %w{host.domain.com Other.Testing.Com} - end - def mkca - Puppet::SSLCertificates::CA.new - end - - def test_clean - dirs = [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir] - ca = mkca - - hosts.each do |host| - files = [] - dirs.each do |dir| - dir = Puppet[dir] - # We handle case insensitivity through downcasing - file = File.join(dir, host.downcase + ".pem") - File.open(file, "w") do |f| - f.puts "testing" - end - files << file - end - assert_nothing_raised do - ca.clean(host) - end - files.each do |f| - assert(! FileTest.exists?(f), "File #{f} was not deleted") - end - end - end - - def test_host2Xfile - ca = mkca - hosts.each do |host| - {:signeddir => :host2certfile, :csrdir => :host2csrfile}.each do |dir, method| - val = nil - assert_nothing_raised do - val = ca.send(method, host) - end - assert_equal(File.join(Puppet[dir], host.downcase + ".pem"), val, - "incorrect response from #{method}") - end - end - end - - def test_list - ca = mkca - # Make a fake csr - dir = Puppet[:csrdir] - list = [] - hosts.each do |host| - file = File.join(dir, host.downcase + ".pem") - File.open(file, "w") { |f| f.puts "yay" } - list << host.downcase - end - - assert_equal(list.sort, ca.list.sort, "list was not correct") - end - - # #142 - test storing the public key - def test_store_public_key - ca = mkca - assert_nothing_raised do - ca.mkrootcert - end - assert(FileTest.exists?(Puppet[:capub]), "did not store public key") - end -end - diff --git a/test/certmgr/support.rb b/test/certmgr/support.rb index 3138c94d7..060c458d8 100755 --- a/test/certmgr/support.rb +++ b/test/certmgr/support.rb @@ -89,8 +89,9 @@ class TestCertSupport < Test::Unit::TestCase should_path = Puppet[:hostprivkey] dir, file = File.split(should_path) - newfile = file.sub(/^([a-z.]+)\./) { $1.upcase + "."} + 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 diff --git a/test/data/providers/host/parsed/valid_hosts b/test/data/providers/host/parsed/valid_hosts new file mode 100644 index 000000000..24636295d --- /dev/null +++ b/test/data/providers/host/parsed/valid_hosts @@ -0,0 +1,19 @@ +# Some leading comment, that should be ignored +# The next line is empty so it should be ignored + +::1 localhost + +# We now try another delimiter: Several tabs +127.0.0.1 localhost + +# No test trailing spaces +10.0.0.1 host1 + +# Ok its time to test aliases +2001:252:0:1::2008:8 ipv6host alias1 +192.168.0.1 ipv4host alias2 alias3 + +# Testing inlinecomments now +192.168.0.2 host3 # This is host3 +192.168.0.3 host4 alias10 # This is host4 +192.168.0.4 host5 alias11 alias12 # This is host5 diff --git a/test/language/functions.rb b/test/language/functions.rb index 1d4ed8241..081063e2b 100755 --- a/test/language/functions.rb +++ b/test/language/functions.rb @@ -451,7 +451,7 @@ class TestLangFunctions < Test::Unit::TestCase scope.function_include("nosuchclass") end - parser.newclass("myclass") + 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}) diff --git a/test/language/parser.rb b/test/language/parser.rb index 5a433c724..6f3d751c2 100755 --- a/test/language/parser.rb +++ b/test/language/parser.rb @@ -39,9 +39,8 @@ class TestParser < Test::Unit::TestCase failers { |file| parser = mkparser Puppet.debug("parsing failer #{file}") if __FILE__ == $0 - assert_raise(Puppet::ParseError, "Did not fail while parsing #{file}") { - parser.file = file - ast = parser.parse + assert_raise(Puppet::ParseError, Puppet::Error, "Did not fail while parsing #{file}") { + Puppet[:manifest] = file config = mkcompiler(parser) config.compile #ast.hostclass("").evaluate config.topscope @@ -97,7 +96,7 @@ class TestParser < Test::Unit::TestCase } 4.times { |i| - path = File.join(basedir, subdir, "subfile#{i}") + path = File.join(basedir, subdir, "subfile#{i}.pp") mkmanifest(path) } @@ -137,8 +136,8 @@ class TestParser < Test::Unit::TestCase end def test_importedclasses - imported = tempfile - importer = tempfile + imported = tempfile '.pp' + importer = tempfile '.pp' made = tempfile @@ -288,7 +287,7 @@ class TestParser < Test::Unit::TestCase ret = parser.parse } - ret.hostclass("").code.each do |obj| + ret.code.each do |obj| assert_instance_of(AST::Collection, obj) end end @@ -362,12 +361,12 @@ file { "/tmp/yayness": assert_raise(Puppet::ParseError) { - parser.parse %{define mydef($schedule) {}} + parser.known_resource_types.import_ast(parser.parse(%{define mydef($schedule) {}}), '') } assert_nothing_raised { - parser.parse %{define adef($schedule = false) {}} - parser.parse %{define mydef($schedule = daily) {}} + parser.known_resource_types.import_ast(parser.parse(%{define adef($schedule = false) {}}), '') + parser.known_resource_types.import_ast(parser.parse(%{define mydef($schedule = daily) {}}), '') } end @@ -379,12 +378,12 @@ file { "/tmp/yayness": str1 = %{if true { #{exec.call("true")} }} ret = nil assert_nothing_raised { - ret = parser.parse(str1).hostclass("").code[0] + ret = parser.parse(str1).code[0] } assert_instance_of(Puppet::Parser::AST::IfStatement, ret) parser = mkparser str2 = %{if true { #{exec.call("true")} } else { #{exec.call("false")} }} - ret = parser.parse(str2).hostclass("").code[0] + ret = parser.parse(str2).code[0] assert_instance_of(Puppet::Parser::AST::IfStatement, ret) assert_instance_of(Puppet::Parser::AST::Else, ret.else) end @@ -393,23 +392,23 @@ file { "/tmp/yayness": parser = mkparser assert_nothing_raised { - parser.parse %{class myclass { class other {} }} + parser.known_resource_types.import_ast(parser.parse(%{class myclass { class other {} }}), '') } assert(parser.hostclass("myclass"), "Could not find myclass") assert(parser.hostclass("myclass::other"), "Could not find myclass::other") assert_nothing_raised { - parser.parse "class base {} + parser.known_resource_types.import_ast(parser.parse("class base {} class container { class deep::sub inherits base {} - }" + }"), '') } sub = parser.hostclass("container::deep::sub") assert(sub, "Could not find sub") # Now try it with a parent class being a fq class assert_nothing_raised { - parser.parse "class container::one inherits container::deep::sub {}" + parser.known_resource_types.import_ast(parser.parse("class container::one inherits container::deep::sub {}"), '') } sub = parser.hostclass("container::one") assert(sub, "Could not find one") @@ -417,7 +416,7 @@ file { "/tmp/yayness": # Finally, try including a qualified class assert_nothing_raised("Could not include fully qualified class") { - parser.parse "include container::deep::sub" + parser.known_resource_types.import_ast(parser.parse("include container::deep::sub"), '') } end @@ -426,20 +425,11 @@ file { "/tmp/yayness": # Make sure we put the top-level code into a class called "" in # the "" namespace - assert_nothing_raised do - out = parser.parse "" - - assert_instance_of(Puppet::Resource::TypeCollection, out) - assert_nil(parser.hostclass(""), "Got a 'main' class when we had no code") - end - - # Now try something a touch more complicated parser.initvars assert_nothing_raised do - out = parser.parse "Exec { path => '/usr/bin:/usr/sbin' }" - assert_instance_of(Puppet::Resource::TypeCollection, out) - assert_equal("", parser.hostclass("").name) - assert_equal("", parser.hostclass("").namespace) + parser.known_resource_types.import_ast(parser.parse("Exec { path => '/usr/bin:/usr/sbin' }"), '') + assert_equal("", parser.known_resource_types.hostclass("").name) + assert_equal("", parser.known_resource_types.hostclass("").namespace) end end @@ -482,22 +472,26 @@ file { "/tmp/yayness": ret = nil assert_nothing_raised do - ret = parser.parse("#{at}file { '/tmp/testing': owner => root }") + parser.known_resource_types.import_ast(parser.parse("#{at}file { '/tmp/testing': owner => root }"), '') + ret = parser.known_resource_types end assert_instance_of(AST::ASTArray, ret.hostclass("").code) resdef = ret.hostclass("").code[0] assert_instance_of(AST::Resource, resdef) - assert_equal("/tmp/testing", resdef.title.value) + assert_instance_of(AST::ASTArray, resdef.instances) + assert_equal(1, resdef.instances.children.length) + assert_equal("/tmp/testing", resdef.instances[0].title.value) # We always get an astarray back, so... check.call(resdef, "simple resource") # Now let's try it with multiple resources in the same spec assert_nothing_raised do - ret = parser.parse("#{at}file { ['/tmp/1', '/tmp/2']: owner => root }") + parser.known_resource_types.import_ast(parser.parse("#{at}file { ['/tmp/1', '/tmp/2']: owner => root }"), '') + ret = parser.known_resource_types end - ret.hostclass("").code.each do |res| + ret.hostclass("").code[0].each do |res| assert_instance_of(AST::Resource, res) check.call(res, "multiresource") end @@ -537,7 +531,7 @@ file { "/tmp/yayness": ret = parser.parse("File #{arrow}") end - coll = ret.hostclass("").code[0] + coll = ret.code[0] assert_instance_of(AST::Collection, coll) assert_equal(form, coll.form) end @@ -560,7 +554,7 @@ file { "/tmp/yayness": res = nil assert_nothing_raised do - res = parser.parse(str).hostclass("").code[0] + res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) @@ -583,7 +577,7 @@ file { "/tmp/yayness": res = nil assert_nothing_raised do - res = parser.parse(str).hostclass("").code[0] + res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) @@ -607,7 +601,7 @@ file { "/tmp/yayness": res = nil assert_nothing_raised("Could not parse '#{test}'") do - res = parser.parse(str).hostclass("").code[0] + res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) @@ -624,15 +618,11 @@ file { "/tmp/yayness": def test_fully_qualified_definitions parser = mkparser + types = parser.known_resource_types assert_nothing_raised("Could not parse fully-qualified definition") { - parser.parse %{define one::two { }} + types.import_ast(parser.parse(%{define one::two { }}), '') } assert(parser.definition("one::two"), "Could not find one::two with no namespace") - - # Now try using the definition - assert_nothing_raised("Could not parse fully-qualified definition usage") { - parser.parse %{one::two { yayness: }} - } end # #524 @@ -655,9 +645,9 @@ file { "/tmp/yayness": end def test_multiple_imports_on_one_line - one = tempfile - two = tempfile - base = tempfile + one = tempfile '.pp' + two = tempfile '.pp' + base = tempfile '.pp' File.open(one, "w") { |f| f.puts "$var = value" } File.open(two, "w") { |f| f.puts "$var = value" } File.open(base, "w") { |f| f.puts "import '#{one}', '#{two}'" } @@ -691,7 +681,7 @@ file { "/tmp/yayness": result = parser.parse %{$variable = undef} } - main = result.hostclass("").code + main = result.code children = main.children assert_instance_of(AST::VarDef, main.children[0]) assert_instance_of(AST::Undef, main.children[0].value) @@ -704,7 +694,8 @@ file { "/tmp/yayness": str = "file { '/tmp/yay': ensure => file }\nclass yay {}\nnode foo {}\ndefine bar {}\n" result = nil assert_nothing_raised("Could not parse") do - result = parser.parse(str) + parser.known_resource_types.import_ast(parser.parse(str), '') + result = parser.known_resource_types end assert_instance_of(Puppet::Resource::TypeCollection, result, "Did not get a ASTSet back from parsing") @@ -734,12 +725,14 @@ file { "/tmp/yayness": result = nil assert_nothing_raised do - result = parser.newclass "Yayness" + parser.known_resource_types.import_ast(parser.parse("class yayness { }"), '') + result = parser.known_resource_types.hostclass('yayness') end assert_equal(result, parser.find_hostclass("", "yayNess")) assert_nothing_raised do - result = parser.newdefine "FunTest" + parser.known_resource_types.import_ast(parser.parse("define funtest { }"), '') + result = parser.known_resource_types.definition('funtest') end assert_equal(result, parser.find_definition("", "fUntEst"), "#{"fUntEst"} was not matched") end diff --git a/test/language/scope.rb b/test/language/scope.rb index cb5558aec..d9c122a92 100755 --- a/test/language/scope.rb +++ b/test/language/scope.rb @@ -163,7 +163,7 @@ class TestScope < Test::Unit::TestCase config = mkcompiler # Create a default source - parser.newclass("") + parser.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "") config.topscope.source = parser.known_resource_types.hostclass("") # And a scope resource @@ -175,12 +175,12 @@ class TestScope < Test::Unit::TestCase ) # Create a top-level define - parser.newdefine "one", :arguments => [%w{arg}], + parser.known_resource_types.add Puppet::Resource::Type.new(:definition, "one", :arguments => [%w{arg}], :code => AST::ASTArray.new( :children => [ resourcedef("file", "/tmp", {"owner" => varref("arg")}) ] - ) + )) # create a resource that calls our third define obj = resourcedef("one", "boo", {"arg" => "parentfoo"}) diff --git a/test/lib/mocha_standalone.rb b/test/lib/mocha_standalone.rb deleted file mode 100644 index ce605811a..000000000 --- a/test/lib/mocha_standalone.rb +++ /dev/null @@ -1,2 +0,0 @@ -require 'mocha/standalone' -require 'mocha/object' diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb index e31a31902..a60092cf7 100755 --- a/test/lib/puppettest.rb +++ b/test/lib/puppettest.rb @@ -6,17 +6,6 @@ mainlib = File.expand_path(File.join(File.dirname(__FILE__), '../../lib')) $LOAD_PATH.unshift(mainlib) unless $LOAD_PATH.include?(mainlib) require 'puppet' - -# include any gems in vendor/gems -Dir["#{mainlib}/../vendor/gems/**"].each do |path| - libpath = File.join(path, "lib") - if File.directory?(libpath) - $LOAD_PATH.unshift(libpath) - else - $LOAD_PATH.unshift(path) - end -end - require 'mocha' # Only load the test/unit class if we're not in the spec directory. @@ -31,16 +20,7 @@ if ARGV.include?("-d") $console = true end -# Some monkey-patching to allow us to test private methods. -class Class - def publicize_methods(*methods) - saved_private_instance_methods = methods.empty? ? self.private_instance_methods : methods - - self.class_eval { public(*saved_private_instance_methods) } - yield - self.class_eval { private(*saved_private_instance_methods) } - end -end +require File.expand_path(File.join(File.dirname(__FILE__), '../../spec/monkey_patches/publicize_methods')) module PuppetTest # These need to be here for when rspec tests use these @@ -205,7 +185,7 @@ module PuppetTest #if rake? or ! Puppet[:debug] #if defined?($puppet_debug) or ! rake? Puppet[:color] = false if textmate? - Puppet::Util::Log.newdestination(@logs) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) if defined? $console Puppet.info @method_name Puppet::Util::Log.newdestination(:console) @@ -227,14 +207,14 @@ module PuppetTest #Facter.stubs(:to_hash).returns({}) end - def tempfile + def tempfile(suffix = '') if defined?(@@tmpfilenum) @@tmpfilenum += 1 else @@tmpfilenum = 1 end - f = File.join(self.tmpdir, "tempfile_" + @@tmpfilenum.to_s) + f = File.join(self.tmpdir, "tempfile_" + @@tmpfilenum.to_s + suffix) @@tmpfiles ||= [] @@tmpfiles << f f @@ -325,7 +305,7 @@ module PuppetTest def logstore @logs = [] - Puppet::Util::Log.newdestination(@logs) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) end end diff --git a/test/lib/puppettest/fakes.rb b/test/lib/puppettest/fakes.rb index aaa711004..712332b74 100644 --- a/test/lib/puppettest/fakes.rb +++ b/test/lib/puppettest/fakes.rb @@ -1,4 +1,4 @@ -require 'puppettest' +require File.expand_path(File.join(File.dirname(__FILE__), '../../../lib/puppet/util')) module PuppetTest # A baseclass for the faketypes. diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index bd04c1ec5..411bad37a 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -94,16 +94,15 @@ module PuppetTest::ParserTesting def resourcedef(type, title, params) title = stringobj(title) unless title.is_a?(AST) + instance = AST::ResourceInstance.new(:title => title, :parameters => resourceparams(params)) assert_nothing_raised("Could not create #{type} #{title}") { return AST::Resource.new( :file => __FILE__, :line => __LINE__, - :title => title, :type => type, - - :parameters => resourceinst(params) + :instances => AST::ASTArray.new(:children => [instance]) ) } end @@ -122,9 +121,7 @@ module PuppetTest::ParserTesting :file => __FILE__, :line => __LINE__, :object => resourceref(type, title), - - :type => type, - :parameters => resourceinst(params) + :parameters => resourceparams(params) ) } end @@ -197,13 +194,13 @@ module PuppetTest::ParserTesting } end - def resourceinst(hash) + def resourceparams(hash) assert_nothing_raised("Could not create resource instance") { params = hash.collect { |param, value| resourceparam(param, value) } - return AST::ResourceInstance.new( + return AST::ASTArray.new( :file => tempfile, diff --git a/test/lib/puppettest/support/assertions.rb b/test/lib/puppettest/support/assertions.rb index 7f326b119..31fa3f1da 100644 --- a/test/lib/puppettest/support/assertions.rb +++ b/test/lib/puppettest/support/assertions.rb @@ -1,8 +1,6 @@ -require 'puppettest' require 'puppettest/support/utils' require 'fileutils' - module PuppetTest include PuppetTest::Support::Utils def assert_logged(level, regex, msg = nil) diff --git a/test/lib/puppettest/support/utils.rb b/test/lib/puppettest/support/utils.rb index edc81d3d6..e022f123c 100644 --- a/test/lib/puppettest/support/utils.rb +++ b/test/lib/puppettest/support/utils.rb @@ -1,5 +1,3 @@ -require 'puppettest' - module PuppetTest::Support end module PuppetTest::Support::Utils @@ -7,6 +5,30 @@ module PuppetTest::Support::Utils Puppet.warning "#{type}: #{ObjectSpace.each_object(type) { |o| }}" end + def basedir(*list) + unless defined? @@basedir + Dir.chdir(File.dirname(__FILE__)) do + @@basedir = File.dirname(File.dirname(File.dirname(File.dirname(Dir.getwd)))) + end + end + if list.empty? + @@basedir + else + File.join(@@basedir, *list) + end + end + + def fakedata(dir,pat='*') + glob = "#{basedir}/test/#{dir}/#{pat}" + files = Dir.glob(glob,File::FNM_PATHNAME) + raise Puppet::DevError, "No fakedata matching #{glob}" if files.empty? + files + end + + def datadir(*list) + File.join(basedir, "test", "data", *list) + end + # # TODO: I think this method needs to be renamed to something a little more # explanatory. @@ -38,10 +60,6 @@ module PuppetTest::Support::Utils config end - # stop any services that might be hanging around - def stopservices - end - # TODO: rewrite this to use the 'etc' module. # Define a variable that contains the name of my user. @@ -84,7 +102,7 @@ module PuppetTest::Support::Utils end def fakefile(name) - ary = [PuppetTest.basedir, "test"] + ary = [basedir, "test"] ary += name.split("/") file = File.join(ary) raise Puppet::DevError, "No fakedata file #{file}" unless FileTest.exists?(file) @@ -140,16 +158,3 @@ module PuppetTest::Support::Utils config end end - -module PuppetTest - include PuppetTest::Support::Utils - - def fakedata(dir,pat='*') - glob = "#{basedir}/test/#{dir}/#{pat}" - files = Dir.glob(glob,File::FNM_PATHNAME) - raise Puppet::DevError, "No fakedata matching #{glob}" if files.empty? - files - end - module_function :fakedata - -end diff --git a/test/other/provider.rb b/test/other/provider.rb index 052d7a0d0..a539ee5a7 100755 --- a/test/other/provider.rb +++ b/test/other/provider.rb @@ -70,24 +70,13 @@ class TestImpl < Test::Unit::TestCase child = @type.provide("child", :parent => parent.name) {} } - assert_nothing_raised { - child.commands :which => "which" - } - - assert(child.command(:which), "Did not find 'which' command") - - assert(child.command(:which) =~ /^\//, - "Command did not become fully qualified") - assert(FileTest.exists?(child.command(:which)), - "Did not find actual 'which' binary") - assert_raise(Puppet::DevError) do child.command(:nosuchcommand) end # Now create a parent command assert_nothing_raised { - parent.commands :sh => Puppet::Util.binary('sh') + parent.commands :sh => Puppet::Util.which('sh') } assert(parent.command(:sh), "Did not find 'sh' command") diff --git a/test/other/report.rb b/test/other/report.rb index b3b41da19..8a909b41c 100755 --- a/test/other/report.rb +++ b/test/other/report.rb @@ -35,10 +35,7 @@ class TestReports < Test::Unit::TestCase config.retrieval_duration = 0.001 trans = config.apply - report = Puppet::Transaction::Report.new - trans.add_metrics_to_report(report) - - report + trans.generate_report end # Make sure we can use reports as log destinations. @@ -95,7 +92,7 @@ class TestReports < Test::Unit::TestCase assert_equal(yaml, File.read(file), "File did not get written") end - if Puppet.features.rrd? + if Puppet.features.rrd? || Puppet.features.rrd_legacy? def test_rrdgraph_report Puppet.settings.use(:main, :metrics) report = mkreport diff --git a/test/puppet/tc_suidmanager.rb b/test/puppet/tc_suidmanager.rb index 449f2aef5..eeb56f2c9 100755 --- a/test/puppet/tc_suidmanager.rb +++ b/test/puppet/tc_suidmanager.rb @@ -80,20 +80,11 @@ class TestSUIDManager < Test::Unit::TestCase warn "Cannot run this test on ruby < 1.8.4" else set_exit_status! - - - Puppet::Util.expects(:execute).with( - 'yay', - { :failonfail => false, - :uid => @user.uid, - - :gid => @user.gid } - ).returns('output') - - - output = Puppet::Util::SUIDManager.run_and_capture 'yay', - @user.uid, - @user.gid + Puppet::Util. + expects(:execute). + with('yay',:combine => true, :failonfail => false, :uid => @user.uid, :gid => @user.gid). + returns('output') + output = Puppet::Util::SUIDManager.run_and_capture 'yay', @user.uid, @user.gid assert_equal 'output', output.first assert_kind_of Process::Status, output.last diff --git a/test/rails/railsparameter.rb b/test/rails/railsparameter.rb index 9f6fc1c1e..77ce33912 100755 --- a/test/rails/railsparameter.rb +++ b/test/rails/railsparameter.rb @@ -22,7 +22,7 @@ class TestRailsParameter < Test::Unit::TestCase # Now create a source parser = mkparser - source = parser.newclass "myclass" + source = parser.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "myclass") host = Puppet::Rails::Host.new(:name => "myhost") diff --git a/test/ral/manager/attributes.rb b/test/ral/manager/attributes.rb index 74a4d0708..6d0284d9e 100755 --- a/test/ral/manager/attributes.rb +++ b/test/ral/manager/attributes.rb @@ -229,7 +229,10 @@ class TestTypeAttributes < Test::Unit::TestCase end yes.each { |a| assert(resource.should(a), "Did not get value for #{a} in #{prov.name}") } no.each do |a| - # These may or may not get passed to the provider. We shouldn't care. + assert_nil(resource.should(a), "Got value for unsupported %s in %s" % [a, prov.name]) + if Puppet::Util::Log.sendlevel?(:info) + assert(@logs.find { |l| l.message =~ /not managing attribute #{a}/ and l.level == :info }, "No warning about failed %s" % a) + end end @logs.clear diff --git a/test/ral/manager/type.rb b/test/ral/manager/type.rb index 7df643005..145877722 100755 --- a/test/ral/manager/type.rb +++ b/test/ral/manager/type.rb @@ -276,7 +276,7 @@ class TestType < Test::Unit::TestCase def test_isomorphic_names catalog = mk_catalog # First do execs, since they're not isomorphic. - echo = Puppet::Util.binary "echo" + echo = Puppet::Util.which "echo" exec1 = exec2 = nil assert_nothing_raised do diff --git a/test/ral/providers/cron/crontab.rb b/test/ral/providers/cron/crontab.rb index 0c87a5bba..be2af1e16 100755 --- a/test/ral/providers/cron/crontab.rb +++ b/test/ral/providers/cron/crontab.rb @@ -97,7 +97,10 @@ class TestCronParsedProvider < Test::Unit::TestCase # Then do them all at once. records = [] text = "" - sample_records.each do |name, options| + # Sort sample_records so that the :empty entry does not come last + # (if it does, the test will fail because the empty last line will + # be ignored) + sample_records.sort { |a, b| a.first.to_s <=> b.first.to_s }.each do |name, options| records << options[:record] text += options[:text] + "\n" end diff --git a/test/ral/providers/host/parsed.rb b/test/ral/providers/host/parsed.rb index c2367d566..955edd5d3 100755 --- a/test/ral/providers/host/parsed.rb +++ b/test/ral/providers/host/parsed.rb @@ -67,7 +67,8 @@ class TestParsedHostProvider < Test::Unit::TestCase # Make sure we convert both directlys correctly using a simple host. def test_basic_isomorphism - hash = {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}} + hash = {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}, + :comment => ''} str = nil assert_nothing_raised do @@ -105,11 +106,13 @@ class TestParsedHostProvider < Test::Unit::TestCase [ {:record_type => :comment, :line => "# comment one"}, {:record_type => :blank, :line => ""}, - {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}}, + {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}, + :comment => ''}, {:record_type => :blank, :line => " "}, {:record_type => :comment, :line => "# another comment"}, - {:record_type => :parsed, :name => "anotherhost", :ip => "192.168.43.57", :host_aliases => []} + {:record_type => :parsed, :name => "anotherhost", :ip => "192.168.43.57", :host_aliases => [], + :comment => ''} ], instances) newtext = nil diff --git a/test/ral/providers/provider.rb b/test/ral/providers/provider.rb index cb0b2a19e..f46e03f82 100755 --- a/test/ral/providers/provider.rb +++ b/test/ral/providers/provider.rb @@ -9,7 +9,7 @@ class TestProvider < Test::Unit::TestCase include PuppetTest def echo - echo = Puppet::Util.binary("echo") + echo = Puppet::Util.which("echo") raise "Could not find 'echo' binary; cannot complete test" unless echo @@ -95,7 +95,7 @@ class TestProvider < Test::Unit::TestCase provider.commands :testing => "/no/such/path" - provider.stubs(:binary).returns "/no/such/path" + provider.stubs(:which).returns "/no/such/path" provider.command(:testing) assert_equal("/no/such/path", provider.command(:testing), "Did not return correct binary path") @@ -187,7 +187,7 @@ class TestProvider < Test::Unit::TestCase dir = tstdir file = File.join(dir, "mycmd") - sh = Puppet::Util.binary("sh") + sh = Puppet::Util.which("sh") File.open(file, "w") { |f| f.puts %{#!#{sh} echo A Failure >&2 diff --git a/test/util/metrics.rb b/test/util/metrics.rb index 1fd57f2f1..82e792d0b 100755 --- a/test/util/metrics.rb +++ b/test/util/metrics.rb @@ -8,7 +8,7 @@ require 'puppettest' require 'puppet/type' class TestMetric < PuppetTest::TestCase - confine "Missing RRDtool library" => Puppet.features.rrd? + confine "Missing RRDtool library" => (Puppet.features.rrd? || Puppet.features.rrd_legacy?) include PuppetTest def gendata @@ -43,7 +43,7 @@ class TestMetric < PuppetTest::TestCase def rundata(report, time) assert_nothing_raised { gendata.each do |name, data| - report.newmetric(name, data) + report.add_metric(name, data) end report.metrics.each { |n, m| m.store(time) } } |
