diff --git a/CHANGELOG.old b/CHANGELOG.old deleted file mode 100644 index bb0be94ba..000000000 --- a/CHANGELOG.old +++ /dev/null @@ -1,1705 +0,0 @@ -This is the legacy CHANGELOG. Please see the new ChangeLog file and the ReleaseNotes page at: - -http://reductivelabs.com/trac/puppet/wiki/ReleaseNotes - -0.25.0 - Fixed #2280 - Detailed exit codes fix - - Fixed #198 - Puppet man pages added - - Moved puppetd, puppetmasterd, puppetrun, puppetca from bin to sbin - - Fixed #2071 - Updated LDAP schema - - Fixed #1849 - Ruby 1.9 portability: `when' doesn't like colons, replace with semicolons - - Fixed #1910 - Updated logcheck regex - - Fixed #1879 - Added to tidy documentation - - Fixed #1881 - Added md5lite explanation - - Fixed #1877 - Tidy type reference update for use of 0 - - Fix autotest on win32 - - Doc strings update for REST - - Fixed #1840 - Bug fixes and improvements for Emacs puppet-mode.el - -0.24.8 - Fixed #2077 - ralsh user broken on OSX - - Fixed #2004 - ssh_authorized_key fails if no target is defined - - Fixed #1629 - incorrect permissions on ssh_authorized_keys created files - - Fixed #2000 - No default specified for checksum - - Fixed #2026 - Red Hat ignoring stop method - - Added ext/dbfix.sql script - fixes common errors in stored configuration databases - - Fixed #1963 - Failing to read /proc/mounts for selinux kills file downloads - - Fixed #2025 - gentoo service provider handle only default init level - - Fixed #1910 - updated logcheck - - Fixed #1871 - Sensitive information leaked in log reports - - Fixed #1956 - Cleaned up variable names to be more sane, clarified error messages - and fixed incorrect use of 'value' variable rather than 'member'. - - Fixed #1831 - Added sprintf function - - Fixed #1830 - Added regsubst function - - Updated up2date and service confines to add support for Oracle EL and VM - - Fixing #1948 and #1953 - augeas ins bug: wrong number of arguments (1 for 3) - - Fixing #944 - changing error message from warning to info - connection recycled - - Fixed #961 - puppetd creating too many/not closing TCP connections - - Fixed #1959 - Added column protection for environment schema migration - - Fixing #1869 - autoloaded files should never leak exceptions - - Fixing #1543 - Nagios parse errors no longer kill Puppet - - Fixed #1420 - nagios_serviceescalation not allowing host_name more than one type - - Fixed #1884 - Exported resources are marked as unexported when collected on the exporting host - - Fixed #1922 - Functions squash all arguments into a single hash - - Fixed #1538 - Yumrepo sets permissions wrongly on files in /etc/yum.repos.d - - Fixed #1936 - Added /* */ support to the vim file - - Fixed #1541 - nagios objects write files to clientbucket on every change - - Fixed #1542 - cannot purge nagios objects - - Fixing #1912 - gid still works with no 'should' value fixing ralsh issues - - Fixing the Rakefile to use 'git format-patch' - - Added README.rst file - - Enhancements to Stored Configuration performance - - Added Reductive Labs build library to tasks directory - - Fixed #1852 - Correct behaviour when no SELinux bindings - - Updated Red Hat spec file 0.24.7 - - Fixed #1920 - Shadow password corruption - -0.24.7 - Fixed #1804 - Added VDev and MultiVDev properties to the ZPool type - - Fixed #1496 - nagios_servicedependency needs a unique host_name? - - Fixed #1420 - nagios_serviceescalation not allowing host_name more than one type - - Bug #1803 Zfs should auto require the ancestor file systems - - Refactor #1802 Use 'zfs get -H -o value' instead of parsing output for value - - Fixing #1800 - tidy now correctly ignores missing files and directories - - Fixing #1794 - returning sync when it is already initialized - - Fixing #1750 again - All of the properties and now :ensure check replace? - - Deprecate the NetInfo nameservice provider. Use directoryservice instead - - Add macauthorization type - - Fixing #1703 - using a mutex around the sending of the tagmails - - Fix #1788 - allow rspec rake to run only some tests - - Fixing the AST constant warnings, using a variable instead of a constant - - Feature #1696 Add support for branded zones - - Feature #1783 - Add ZFS support - - type/mcx.rb Feature #1026 - MCX Type - - Fixing #1749 - Splay now hopefully behaves "better" for small values - - Fix #1741 - Add inline_template function - - Slight denormalisation to store a host's environment as a first class - - Added Rake :ci namespace and CI tasks - - Refactoring the thread-safety in Puppet::Util - - Removing the included testing gems; you must now install them yourself - - Refactoring of SELinux functions to use native Ruby SELinux interface - - Removing all mention of EPM, RPM, or Sun packages. - - Fixed #1496 - nagios_servicedependency needs a unique host_name? - - Fixed #1420 - nagios_serviceescalation not allowing host_name more than one type - - Fixed #1695 - Solaris 10 zone provider doesn't properly handle unknown zone attributes in newer releases - - Fixed #1776 - Trivial fix for gentoo service provider - - Fixed #1767 - Minor fix to emacs mode - - Fixed #1711 - fileserver test fails due to incorrect mocking - - Fixed #1751 - Mac OS X DirectoryService nameservice provider support for - plist output and password hash fil - - Fixed #1752 - Add an optional argument to Puppet::Util.execute to determine - whether stderr and stdout are combined in the output - - Added versionable feature to the RPM provider - - Fixed #1668 - puppetca can't clean unsigned certs - - Moved RRD feature from util/metric.rb to feature/base.rb - - Fixed #1735 and #1747 - Fixes to confine system - - Fixed #1681 - Add filesystem type check to test for per-file SELinux context support - - Fixed #1746 - Sync SELinux file attributes after file contents created/modified - - Replaced SELInux calls to binaries with Ruby SELinux bindings - - Fixed #1748 - Include spec directory in packages - - Fixes #1672 - unsafe crontab handling in Solaris - - Fixed #1718 - Added preseed to apt uninstall and purge - - Fixed #1739 - Added uninstall functionality to yum provider - - Fixed #1710 - Spurious output in test run - - Fixed #1667 - Documentation should specify natural language regexs, not Regexp objects - - Fixed #1692 - k5login fails to set mode when file is created - - Fixed #1660 - Added specific recurse values for tidy - - Fixed #1698 - All logs should now show up in the reports - - Fixed #1661 - Type reference: tidy should specify manditory parameters - - Fixed #1104 - Classes and nodes should set $name variables - - Updated Red Hat spec file for 0.24.6 - - Removed conf/debian directory - Debian packaging information - now maintained downstream - - Added augeas type - - Added support for @doc type and manifest documentation support - see: - http://reductivelabs.com/trac/puppet/wiki/PuppetManifestDocumentation - - Added multiline comment support - -0.24.6 - Adding support to the user type for: profiles, auths, project, - key/value pairs (extension to Solaris RBAC support added in - 0.24.6) - - Fixed #1662 - Configuration Reference still references 'section' - - Fixed #1460 - enhance redhat puppetmaster init.d script to easy start puppetmaster as a mongrel cluster - - Fixed #1663 - Regression relating to facter fact naming from 0.24.5 - - Fixed #1655 - Provider::Confine::Variable tests are broken - - Fixed #1646 - service puppet status does not work as non-root - on redhat system - - Fixed #1649 - Updated OSX package cleanup - - Fixed #1647 - puppetdoc -r providers now working again - - Fixed #1639 - uninitialized constant Puppet::Type::User::ProviderUseradd - - Fixed #1637 - With an inexistant (global) templatedir, modules - can't access their templates - - Fixed #1202 - Collection attribute matching doesn't parse arrays - - Fixed #1473 - Puppetd stops with error after puppetmasterd - is unavailable - - Fixed #1354 - yum provider problems with RHEL 3 - - Fixed #1633 - Added support for --detailed-exits to bin/puppet - - Fixed #381 - Allow Allow multiple overrides in one statement - - Fixing #947 - pluginsync no longer fails poorly when no plugins exist - - Fixed #981 - Removed 'Adding aliases' info message - - Fixing #1089 - Log messages are now tagged with the log level, - making it easier to match messages in the 'tagmail' report. - - Fixing #1098 - Multiline strings now correctly increment the line count - - Fixing #1614 - Environments no longer have to be listed out - - Fixed #1628 - Changed node search to use certname rather than Facter - hostname - - Fixed #1613 - The client environment will be substituted when looking - up settings. - - Updated puppet binary documentation - - Feature #1624 - Added RBAC roles to solaris user provider - - Fixed #1586 - Specifying "fully qualified" package names in Gentoo - - Fixed #1620 - Add 'sles' to Puppet confines when 'suse' is used - - Fixed #1585 - Allow complex 'if' and variable expressions - - Fixed #1564 - Saving File#checksum to state.yaml broken - - Fixed #1603 - Added support for running Puppet inside a Rack application - (mod_rails) with Passenger and Apache - - Fixed #1596 - Deploying file resources with ++ generates error - - Modified the group and zone resource types to no longer call - 'currentpropvalues' as a means of setting all values to absent. - There should be no behaviour change from this change. - - Modified the behaviour of resource-level 'retrieve' -- it only - calls 'retrieve' on each property if the resource exists. - - Fixed #1622 - Users and their groups should again add in one transaction - - Fixed #791 - You should now be able to create and find a user/group in one transaction. - - Fixed #1610 - Raise "Filebucketed" messages to Notice priority - - FIxed #1530 - ssh_authorized_keys provider does not crash anymore on SSH type 1 keys - - Added a number of confines to package providers - - Fixed #1609 - Added confines for the Gentoo, FreeBSD and - SMF (Solaris) service providers - - Fixed #1608 - Added ubuntu to defaultfor for apt provider - - Fixed #1607 - Added ubuntu to defaultfor for Debian service - provider - - Fixed #1045 - Multiple metaparams all get added to resources. - - Fixed #1472 -- defined, exported resources in the current compile - now get expanded correctly. - - Fixed #1595 - Internally, Property#retrieve is no longer called - when no 'should' value is available for a resource. - - Fixed #1588 - Fixed puppetca --clean --all - - Fixed #1584 - Added support for appended variables - - Fixed #1554 - Added support for multiple template directories - - Fixed #1500 - puppetrun not working - - Fixed #1579 and #1580 - errors in the Puppet RPM spec file - - Fixed #1572 -- file purging now fails if remote sources do not exist. - - Fixed #1521 -- ldap user and password are now used with the default connection. - - Fixed issues with file descriptors leaking into subprocesses - - Fixed #1568 - createpackage.sh - - Fixed #1571 - Puppet::Util::binary returns incorrect results - - Fixed #1553 - Puppet and Facter cannot both install the plist module into two different locations - - Adjusted hpuxuseradd user provider to confine to HP-UX and fixed HP-UX user provider path regression - - Fixed debug messages in package type - thanks to Todd Zullinger for this fix - - Fixed #1566 - changed password property of the user type - - Fixed debug messages in package type - - Updated Red Hat spec file - - Fixes #1455 - Adds HP-UX support for user type - - Fixes #1551 puppetmaster.freshness xmlrpc call returns incorrect type - - Fixes #1554 - Fix exception for undefined hostname - - Fixed #1533 - changed permissions for man directory - - Added daemontools and runit providers for service type - - Added simple rake task for running unit tests - - Added spec Rake task - - Fixed #1526 - Fixed leak in template - - Fixed #1506 - Removed storeconfig duplicate indexes - - Fixed #1457 - case insensitive match for error - - Fixed #1488 - Moved individual functions out of functions.rb into - lib/puppet/parser/functions directory. New functions should be create in this directory. - - Fixed #1508 - Added HP-UX package provider - - Fixed #1502 - Fixed poor stored configuration performance - - Fixed #1510 - Storeconfiguration fixed for Rails 2.1 - - Add the -P/--ping option to puppetrun, fixes #1501 - - Fixed #1394 - Added stored configuration clearing script to /ext - - Fixed #1442 - replaced use of Facter for report titling with certname - - Fixed $1456 - add proxy configuration capability to yum repo - - Fixed #1457 - removed confine warning - - A working script to create an OS X pkg out of the Puppet repository - - Fixed #1441 - Updated console colours - - Expose all puppet variables as instance member variables of the template wrapper. - This helps resolve redmine #1427, by providing a safe mechanism to access variables. - - * Implement Puppet::Parser::Scope#to_hash, which returns a hash containing all the - variable bindings in the current and, optionally, parent scope. - * Use that to set instance member variables into Puppet::Parser::Templatewrapper - * Report the time taken for variable binding at debug level, to help identify any - performance regression that is encountered in the real world. - * Rename the @scope and @file members of the template wrapper, to avoid clashing - with a scope variable exposed within puppet. - - Ensure that we consistently use either string #{} interpolation or String.% - interpolation, not both, to avoid issues where a #{} interpolated value - contains a % character. - - Feature #1476: Allow specification of --bindir --sbindir --sitelibdir --mandir --destdir - in installation - - Added feature #1241 : Improve performance of group lookups - - Fixed bug #1448: Puppet CA incorrectly writes out all certs to inventory .txt on each - certificate signing - - Fixing puppetlast to make it work with 0.24.5 / 0.25. Made puppetlast work on 0.24.5 - by using the YAML indirector - -0.24.5 - You can now select the encoding format when transferring the catalog, - with 'yaml' still being the default but 'marshal' being an option. - This is because testing has shown drastic performance differences - between the two, with up to 70% of compile time being spent - in YAML code. Use the 'catalog_format' setting to choose your format, - and the setting must be set on the client. - - Fixed #1431 - Provider confines must now specify similar tests in one call. - I.e., you can't do confine :operatingsystem => %w{a b} and then - confine :operatingsystem => %w{b c}; you'd need to do them in one command. - This now-obsolete behaviour does not seem to be used anywhere. - The fix for #1431 is actually just removing the tests that exposed - this change; the change happened when I refactored how confines work. - - Removed faulty interface type - - Updated /spec/unit/rails.rb test - - Fix #1426 - services on redhat are restarted again and status is - called from the Red Hat provider - - Fixed #1414 - Return code from waitpid now right shifted 8 bits - - Fixed #174 - a native type type for managing ssh authorized_keys - files is available. - - Further moves from the examples directory and ext directory - - Fixed #1397 One line fix, fail instead of log - - Moved debian to conf and updated examples directory - - Fixed #1368 - updated Red Hat init scripts - - Added message referencing ReductiveLabs build library - - Fixed #1396 - Added sha1 function from DavidS to core - - Fixed #1399 - the ldap user provider now knows it can manage - passwords. - - Fixed #1272 - if you provide a group name as the gid to an ldap - user, the name will be converted to a gid. Note that this only - looks up ldap groups, at this point; if you want to set an ldap - user's primary group to a local group, you have to specify the GID. - - Fixed #1226 - gems can now specify source repositories. - - Fixed #1232 - the rundir no longer specifies a user/group, - and there are now client- and server-specific yaml directories. - - Fixed 1240 - puppet will function more like puppetd if graphing - or reporting are enabled. - - Fixed #1231 - Exceptions during initialization should now be clearer. - - Fixed #1006 - puppetrun --class works again. I added the class - membership testing to the Ldap node terminus, and added tests, - so it shouldn't break again. - - Fixed #1114 - Facts in plugin directories should now be autoloaded, - as long as you're using Facter 1.5. - - Removed support for the 'node_name' setting in LDAP and external node lookups. - Fixed #1195 - Updated Gentoo init scripts - - Fixed #1367 - Updated Rakefile for new daily builds - - Fixed #1370 - removed test/util/loadedfile.rb tests - - Fixed #1221 - aliases to titles now work for resources. - - Fixed #1012 - templates in the templatedir are preferred to module templates. - - Fixed #707 - special '@reboot'-style cron jobs work again. - - Fixed #1360 - allowdupe works on groups again. - - Fixed #1369 - the init service provider now supports HP-UX. - - Removed support for the 'node_name' setting in LDAP and external node - lookups. - - Also removed support for 'default' nodes in external nodes. - LDAP nodes now use the certificate name, the short name, and 'default', - but external nodes just use the certificate name and any custom terminus - types will use just the certificate name. - - Fixing #1168 (for 0.24.x) -- automatically downcasing the fqdn. - Also requiring that passed in certnames be downcased; the setting - system isn't currently flexible enough to automatically downcase - it for the user. - - Adding a ResourceTemplate class for using templates directly - within resources (i.e., client-side templates). This would really - only be used for composite resources that pass the results of the - template on to generated resources. - - Exporting or collecting resources no longer raises an exception - when no storeconfigs is enabled, it just produces a warning. - - Always using the cert name to store yaml files, which fixes #1178. - The Master handler previously provided the support for the :node_name - setting, and that functionality has now been moved into the Node - class. At the same time, the names to search through have been - changed somewhat: Previously, the certificate name and the - hostname were both used for searching, but now, the cert name - is always searched first (unless node_name == facter), but only - the Facter hostname, domain, and fqdn are used otherwise. We no - longer split the cert name, only the hostname/domain/fqdn. - - Fixing transaction support for prefetching generated resources. - - Adding support for settings within the existing Facter provider confines. - - Moving all confine code out of the Provider class, and fixing #1197. - Created a Confiner module for the Provider class methods, enhanced - the interface between it and the Confine class to make sure binary - paths are searched for fresh each time. - - Modified the 'factpath' setting to automatically configure - Facter to load facts there if a new enough version of - Facter is used. - - Crontab provider: fix a parse error when a line begins with a space - character (fixes #1216) - - Instead of deleting the init scripts (with --del) we should simply - disable it with chkconfig service off, and respectfully do the same - for enable => true; - - Added ldap providers for users and groups. - - Added support for the --all option to puppetca --clean. If - puppetca --clean --all is issued then all client certificates - are removed. - - Resources now return the 'should' value for properties from - the [] accessor method (they previously threw an exception when - this method was used with properties). This shouldn't have any - affect functionally; it just makes the method equivalent to 'should' - for properties, but it works for all attribute types now. - - Modified the 'master' handler to use the Catalog class to - compile node configurations, rather than using the Configuration - handler, which was never used directly. I removed the Configuration - handler as a result. - - Modified the 'master' handler (responsible for sending configurations - to clients) to always return Time.now as its compile date, so - configurations will always get recompiled. - - Fixed #1184 -- definitions now autoload correctly all of the time. - - Removed the code from the client that tries to avoid recompiling - the catalog. The client will now always recompile, assuming it - can reach the server. It will still use the cached config if - there's a failure. - - Fixing #1173 -- classes and definitions can now have the same - name as a directory with no failures. - - Saving new facts now expires any cached node information. - - Switching how caching is handled, so that objects now all - have an expiration date associated with them. This makes it - much easier to know whether a given cached object should be used - or if it should be regenerated. - - Changing the default environment to production. - -0.24.4 - Pass source to pkg_add via the PKG_PATH environment variable if - it ends in a '/' indicating it is a directory. Allows pkg_add - to resolve dependancies, and make it possible to specify packages - without version numbers. - - Fixing #571 -- provider suitability is now checked at resource - evaluation time, rather than resource instantiation time. This - means that you don't catch your "errors" as early, but it also - means you should be able to realistically configure a whole host - in one run. - - Moved the configuration of the Node cache to the puppetmasterd - executable, since it otherwise causes caches to be used in all - cases, which we don't want (e.g., bin/puppet was using them). - - Ported #198 man page creation functionality to 0.24.x branch and - added man pages and man page creation logic to install.rb. The - man pages are stored in man/man8 and will install to config::CONFIG - mandir/man8. - - Fixing #1138 -- the yamldir is automatically created by the - server now that it's in the :puppetmasterd section rather than - a separate :yaml section. - - Disabling http keep-alive as a means of preventing #1010. - There is now a constant in Puppet::Network::HttpPool that will - disable or enable this feature, but note that we determined - that it can cause corruption, especially in file serving (but - it's client-side corruption). - - Applying patch by Ryan McBride to fix OpenBSD package - matching. The actual problem was caused by the fix to #1001. - - Found all instances of methods where split() is used without - any local variables and added a local variable -- see - http://snurl.com/21zf8. My own testing showed that this - caused memory growth to level off at a reasonable level. - Note that the link above says the problem is only with class - methods, but my own testing showed that it's any method that - meets these criteria. This is not a functional change, but - should hopefully be the last nail in the coffin of #1131. - - Found an array that leaked pretty quickly between reparsing - files, thanks to work by Adam Jacob and Arjuna Christenson - (the finding, not the leak). I'm going to act like this - fixes #1131, at least for now, but I doubt it does, - since that shows general memory growth over time, whereas - the leak here should go away as soon as files are reparsed - (because the parser is holding the reference to the leaking - array). - - Fixed #1147: Cached nodes are correctly considered out of - date if the node facts have been updated (thus causing - node facts to again be available in manifests, for those - cases where they were not). - - Fixed #1137: The certificate name is correctly being added - to the facts hash. - - Fixed #1136: Verbose and Debug no longer clobber each other. - - Hopefully *finally* fixed the "already being managed" problem - (#1036). The problem only cropped up if there was a failure - when trying to manage the system -- this would cause the - setting-based resources not to get cleaned up. - -0.24.3 - Modified the ldap node terminus to also use the facts version - as the version for a node, which should similarly encourage the - use of the yaml cache. (Related to #1130) - - Caching node information in yaml (I figured caching in memory will - cause ever-larger memory growth), and changing the external node - terminus to use the version of the facts as their version. This - will usually result in the cached node information being used, - instead of always hitting the external node app during file - serving. Note that if the facts aren't changed by the client, - then this will result in the cached node being used, but at this - point, the client always updates its facts. (#1130) - - Fixing #1132 -- host names can now have dashes anywhere. - (Patch by freiheit.) - - Fixing #1118 -- downloading plugins and facts now ignores noop. - Note that this changes the behaviour a bit -- the resource's - noop setting always beats the global setting (previously, - whichever was true would win). - - The change in checksums from 'timestamp' to 'mtime' no longer - result in updates on every run (#1116). - - Aliases again work in relationships (#1094). - - The CA serial file will no longer ever be owned by - root (#1041). - - Fixing the rest of #1113: External node commands can specify - an environment and Puppet will now use it. - - Partially fixing #1113: LDAP nodes now support environments, - and the schema has been updated accordingly. - - Always duplicating resource defaults in the parser, so that - stacked metaparameter values do not result in all resources - that receive a given default also getting those stacked - values. - -0.24.2 - Fixing #1062 by moving the yamldir setting to its own yaml - section. This should keep the yamldir from being created - on clients. - - Fixed #1047 -- Puppet's parser no longer changes the order - in which statements are evaluated, which means that case - statements can now set variables that are used by other - variables. - - Fixed #1063 -- the master correctly logs syntax errors when - reparsing during a single run. - - Removed the loglevels from the valid values for `logoutput` - in the Exec resource type -- the log levels are specified - using the `loglevel` parameter, not `logoutput`. This never - worked, or at least hasn`t for ages, and now the docs are - just correct. - - Somewhat refactored fileserving so that it no longer caches - any objects, nor does it use Puppet's RAL resources. In the - process, I fixed #894 (you can now copy links) and refactored - other classes as necessary. Mostly it was fixing tests. - - Hopefully partially fixed #1010 -- clients should now fail - to install files whose checksums do not match the checksum - from the server. - - Fixed #1018 -- resources now have their namevars added as - aliases in the resource catalog, just like they were added - in the resource classes. - - Fixed #1037 -- remote unreadable files no longer have the - permission denied exceptions caught, thus forbidding them - from being replaced with 'nil'. - - The environment is now available as a variable in the manifests. - - Fixed #1043 -- autoloading now searches the plugins directory - in each module, in addition to the lib directory. The 'lib' - directory is also deprecated, but supported for now to give - people a chance to convert. - - Fixed #1003 -- Applying DavidS's patch to fix searching for - tags in sql. - - Fixed #992 -- Puppet is now compatible with gems 1.0.1. - - Fixed #968 again, this time with tests -- parseonly works, - including not compiling the configurations, and also storeconfigs - is no longer required during parse-testing. - - Fixed #1021 -- the problem was that my method of determining - the in-degree sometimes resulted in a lower number than the - number of in-edges. - - Fixed #997 -- virtual defined types are no longer evaluated. - NOTE: This introduces a behaviour change, in that you previously - could realize a resource within a virtual defined resource, and now - you must realize the entire defined resource, rather than just - the contained resource. - - Fixed #1030 - class and definition evaluation has been significantly - refactored, fixing this problem and making the whole interplay - between the classes, definitions, and nodes, and the Compile class much - cleaner. - - Exec resources must now have unique names, although the commands can still - be duplicated. This is easily accomplished by just specifying a unique - name with whatever (unique or otherwise) command you need. - - Fixed #989 -- missing CRL files are correctly ignored, and the - value should be set to 'false' to explicitly not look for these - files. - - Fixed #1017 -- environment-specific modulepath is no longer ignored. - - Fixing #794 -- consolidating the gentoo configuration files. - - Fixing #976 -- both the full name of qualified classes and - the class parts are now added as tags. I've also - created a Tagging module that we should push throughout - the rest of the system that uses tags. - - Fixing #995 -- puppetd no longer dies at startup if the server - is not running. - - Fixing #977 -- the rundir is again set to 1777. - - Fixed #971 -- classes can once again be included multiple - times. - - Added builtin support for Nagios types using - Naginator to parse and generate the files. - -0.24.1 - Updated vim filetype detection. (#900 and #963) - - Default resources like schedules no longer conflict with - managed resources. (#965) - - Removing the ability to disable http keep-alive, since - it didn't really work anyway and it should no longer - be necessary. - - Refactored http keep-alive so it actually works again. - This should be sufficient enough that we no longer need the - ability to disable keep-alive. There is now a central - module responsible for managing HTTP instances, along with - all certificates in those instances. - - Fixed a backward compatibility issue when running 0.23.x - clients against 0.24.0 servers -- relationships would - consistently not work. (#967) - - Closing existing http connections when opening a new one, - and closing all connections after each run. (#961) - - Removed warning about deprecated explicit plugins mounts. - -0.24.0 (misspiggy) - Modifying the behaviour of the certdnsnames setting. It now defaults - to an empty string, and will only be used if it is set to something - else. If it is set, then the host's FQDN will also be added as - an alias. The default behaviour is now to add 'puppet' and - 'puppet.$domain' as DNS aliases when the name for the cert being - signed is equal to the signing machine's name, which will only - be the case for CA servers. This should result in servers always - having the alias set up and no one else, but you can still override - the aliases if you want. - - External node support now requires that you set the 'node_terminus' - setting to 'exec'. See the IndirectionReference on the wiki for more - information. - - http_enable_post_connection_check added as a configuration - option for puppetd. This defaults to true, which validates the server - SSL certificate against the requested host name in new versions of ruby. - See #896 for more information. - - Mounts no longer remount swap filesystems. - - Slightly modifying how services manage their list of paths - (and adding documention for it). Services now default - to the paths specified by the provider classes. - - Removed 'type' as a valid attribute for services, since it's been - deprecated since the creation of providers. - - Removed 'running' as a valid attribute for services, since it's - been deprecated since February 2006. - - Added modified patch by Matt Palmer which adds a 'plugins' mount, - fixing #891. See PluginsInModules on the wiki for information on - usage. - - Empty dbserver and dbpassword settings will now be ignored when - initializing Rails connections (patch by womble). - - Configuration settings can now be blank (patch by womble). - - Added calls to endpwent/endgrent when searching for user and group IDs, - which fixes #791. - - Obviated 'target' in interfaces, as all file paths were automatically - calculated anyway. The parameter is still there, but it's - not used and just generates a warning. - - Fixing some of the problems with interface management on Red Hat. - Puppet now uses the :netmask property and does not try to set - the bootproto (#762). - - You now must specify an environment and you are required to specify - the valid environments for your site. (#911) - - Certificates now always specify a subjectAltName, but it defaults - to '*', meaning that it doesn't require DNS names to match. You - can override that behaviour by specifying a value for - 'certdnsnames', which will then require that hostname as a match (#896). - - Relationship metaparams (:notify, :require, :subscribe, and - :before) now stack when they are collecting metaparam values - from their containers (#446). For instance, if a resource - inside a definition has a value set for 'require', and you call - the definition with 'require', the resource gets both requires, - where before it would only retain its initial value. - - Changed the behavior of --debug to include Mongrel client - debugging information. Mongrel output will be written to - the terminal only, not to the puppet debug log. This should - help anyone working with reverse HTTP SSL proxies. (#905) - - Fixed #800 -- invalid configurations are no longer - cached. This was done partially by adding a relationship - validation step once the entire configuration is created, - but it also required the previously-mentioned changes - to how the configuration retrieval process works. - - Removed some functionality from the Master client, - since the local functionality has been replaced - with the Indirector already, and rearranging how configuration - retrieval is done to fix ordering and caching bugs. - - The node scope is now above all other scopes besides - the 'main' scope, which should help make its variables - visible to other classes, assuming those classes were - not included in the node's parent. - - Replaced GRATR::Digraph with Puppet::SimpleGraph as - the base class for Puppet's graphing. Functionality - should be equivalent but with dramatically better - performance. - - The --use-nodes and --no-nodes options are now obsolete. - Puppet automatically detects when nodes are defined, and if - they are defined it will require that a node be found, - else it will not look for a node nor will it fail if it - fails to find one. - - Fixed #832. Added the '--no-daemonize' option to puppetd and - puppetmasterd. NOTE: The default behavior of 'verbose' and - 'debug' no longer cause puppetd and puppetmasterd to not - daemonize. - - Added k5login type. (#759) - - Fixed CA race condition. (#693) - - Added shortname support to config.rb and refactored addargs - -0.23.2 - Fixed the problem in cron jobs where environment settings - tended to multiple. (#749) - - Collection of resources now correctly only collects exported - resources again. This was broken in 0.23.0. (#731) - - 'gen_config' now generates a configuration with - all parameters under a heading that matches the - process name, rather than keeping section headings. - - Refactored how the parser and interpreter relate, - so parsing is now effectively an atomic process (thus - fixing #314 and #729). This makes the interpreter less - prone to error and less prone to show the error to the - clients. Note that this means that if a configuration - fails to parse, then the previous, parseable configuration - will be used instead, so the client will not know that - the configuration failed to parse. - - Added support for managing interfaces, thanks to work - by Paul Rose. - - Fixed #652, thanks to a patch by emerose; --fqdn again - works with puppetd. - - Added an extra check to the Mongrel support so that - Apache can be used with optional cert checking, instead - of mandatory, thus allowing Mongrel to function as the CA. - This is thanks to work done by Marcin Owsiany. - -0.23.1 (beaker) - You can now specify relationships to classes, which work - exactly like relationships to defined types: - require => Class[myclass] - This works with qualified classes, too. - - You can now do simple queries in a collection of - exported resources. You still cannot do multi-condition queries, - though. (#703) - - puppetca now exits with a non-zero code if it cannot - find any host certificates to clean. (Patch by Dean - Wilson.) - - Fully-qualified resources can now have defaults. (#589) - - Resource references can now be fully-qualified names, - meaning you can list definitions with a namespace as - dependencies. (#468) - - Files modified using a FileType instance, as ParsedFile - does, will now automatically get backed up to the filebucket - named "puppet". - - Added a 'maillist' type for managing mailing lists. - - Added a 'mailalias' type for managing mail aliases. - - Added patch by Valentin Vidic that adds the '+>' syntax to - resources, so parameter values can be added to. - - The configuration client now pulls libraries down to $libdir, - and all autoloading is done from there with full support - for any reloadable file, such as types and providers. (#621) - Note that this is not backward compatible -- if you're using - pluginsync right now, you'll need to disable it on your clients - until you can upgrade them. - - The Rails log level can now be set via (shockingly!) the - 'rails_loglevel' parameter (#710). Note that this isn't - exactly the feature asked for, but I could not find a - way to directly copy ActiveRecord's concept of an environment. - - External node sources can now return undefined classes (#687). - - Puppet clients now have http proxy support (#701). - - The parser now throws an error when a resource reference - is created for an unknown type. Also, resource references - look up defined types and translate their type accordingly. (#706) - - Hostnames can now be double quoted. - - Adding module autoloading (#596) -- you can now 'include' classes - from modules without ever needing to specifically load them. - - Class names and node names now conflict (#620). - -0.23.0 - 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. - - Fixed environment handling in the crontab provider (#669). - - Added patch by trombik in #572, supporting old-style - freebsd init scripts with '.sh' endings. - - Added fink package provider (#642), as provided by 'do'. - - Marked the dpkg package provider as versionable (#647). - - Applied patches by trombik to fix FreeBSD ports (#624 and #628). - - Fixed the CA server so that it refuses to send back a certificate - whose public key doesn't match the CSR. Instead, it tells the - user to run 'puppetca --clean'. - - Invalid certificates are no longer written to disk (#578). - - Added a package provider (appdmg) able to install .app packages - on .dmg files on OS X (#641). - - Applied the patch from #667 to hopefully kill the client hanging - problems (permanently, this time). - - Fixed functions so that they accept most other rvalues as valid values - (#548). - - COMPATIBILITY ALERT: - Significantly reworked external node support, in a way that's NOT - backward-compatible: - - Only ONE node source can be used -- you can use LDAP, code, or - an external node program, but not more than one. - - LDAP node support has two changes: First, the "ldapattrs" attribute is - now used for setting the attributes to retrieve from the server (in - addition to required attriutes), and second, all retrieved attributes - are set as variables in the top scope. This means you can set attributes - on your LDAP nodes and they will automatically appear as variables - in your configurations. - - External node support has been completely rewritten. These programs must - now generate a YAML dump of a hash, with "classes" and "parameters" keys. - The classes should be an array, and the parameters should be a hash. The - external node program has no support for parent nodes -- the script must - handle that on its own. - - Reworked the database schema used to store configurations with the - storeconfigs option. - - Replaced the obsolete RRD ruby library with the maintained - RubyRRDtool library (which requires rrdtool2) (#659). - - The Portage package provider now calls eix-update automatically - when eix's database is absent or out of sync (#666). - - Mounts now correctly handle existing fstabs with no pass or dump values - (#550). - - Mounts now default to 0 for pass and dump (#112). - - Added urpmi support (#592). - - Finishing up the type => provider interface work. Basically, package - providers now return lists of provider instances. In the proces, - I rewrote the interface between package types and providers, and also - enabled prefetching on all packages. This should significantly speed - up most package operations. - - Hopefully fixing the file descriptor/open port problems, with patches - from Valentin Vidic. - - Significantly reworked the type => provider interface with respect to - listing existing provider instances. The class method on both - class heirarchies has been renamed to 'instances', to start. Providers - are now expected to return provider instances, instead of creating - resources, and the resource's 'instances' method is expected to - find the matching resource, if any, and set the resource's - provider appropriately. This *significantly* reduces the reliance on - effectively global state (resource references in the resource classes). - This global state will go away soon. - - Along with this change, the 'prefetch' class method on providers now - accepts the list of resources for prefetching. This again reduces - reliance on global state, and makes the execution path much easier - to follow. - - Fixed #532 -- reparsing config files now longer throws an exception. - - Added some warnings and logs to the service type so - users will be encouraged to specify either "ensure" - or "enabled" and added debugging to indicate why - restarting is skipped when it is. - - Changed the location of the classes.txt to the state - directory. - - Added better error reporting on unmatched brackets. - - Moved puppetd and puppetmasterd to sbin in svn and fixed install.rb - to copy them into sbin on the local system appropriately. (#323) - - Added a splay option (#501). It's disabled when running under - --test in puppetd. The value is random but cached. It defaults - to the runinterval but can be tuned with --splaylimit - - Changing the notify type so that it always uses - the loglevel. - - Fixing #568 - nodes can inherit from quoted node names. - - Tags (and thus definitions and classes) can now be a single - character. (#566) - - Added an 'undef' keyword (#629), which will evaluate to "" - within strings but when used as a resource parameter value - will cause that parameter to be evaluated as undefined. - - Changed the topological sort algorithm (#507) so it will always - fail on cycles. - - Added a 'dynamicfacts' configuration option; any facts in that - comma-separated list will be ignored when comparing facts to - see if they have changed and thus whether a recompile is necessary. - - Renamed some poorly named internal variables: - @models in providers are now either @resource or - @resource_type (#605). - - @children is no longer used except by components (#606). - - @parent is now @resource within parameters (#607). - - The old variables are still set for backward compatibility. - - Significantly reworking configuration parsing. Executables all now - look for 'puppet.conf' (#206), although they will parse the old-style - configuration files if they are present, although they throw a deprecation - warning. Also, file parameters (owner, mode, group) are now set on the - same line as the parameter, in brackets. (#422) - - Added transaction summaries (available with the --summarize option), - useful for getting a quick idea of what happened in a transaction. - Currently only useful on the client or with the puppet interpreter. - - Changed the interal workings for retrieve and removed the :is attribute - from Property. The retrieve methods now return the current value of - the property for the system. - - Removed acts_as_taggable from the rails models. - -0.22.4 - Execs now autorequire the user they run as, as long as the user - is specified by name. (#430) - - Files on the local machine but not on the remote server during - a source copy are now purged if purge => true. (#594) - - Providers can now specify that some commands are optional (#585). - Also, the 'command' method returns nil on missing commands, - rather than throwing an error, so the presence of commands - be tested. - - The 'useradd' provider for Users can now manage passwords. - No other providers can, at this point. - - Parameters can now declare a dependency on specific - features, and parameters that require missing features - will not be instantiated. This is most useful for - properties. - - FileParsing classes can now use instance_eval to add - many methods at once to a record type. - - Modules no longer return directories in the list of found - manifests (#588). - - The crontab provider now defaults to root when there is no - USER set in the environment. - - Puppetd once again correctly responds to HUP. - - Added a syntax for referring to variables defined in - other classes (e.g., $puppet::server). - - STDIN, STDOUT, STDERR are now redirected to /dev/null in - service providers descending from base. - - Certificates are now valid starting one day before they are - created, to help handle small amounts of clock skew. - - Files are no longer considered out of sync if some properties - are out of sync but they have no properties that can create - the file. - -0.22.3 - Fixed backward compatibility for logs and metrics from older clients. - - Fixed the location of the authconfig parameters so there aren't - loading order issues. - - Enabling attribute validation on the providers that subclass - 'nameservice', so we can verify that an integer is passed to - UID and GID. - - Added a stand-alone filebucket client, named 'filebucket'. - - Fixed the new nested paths for filebuckets; the entire md5 sum was - not being stored. - - Fixing #553; -M is no longer added when home directories are being - managed on Red Hat. - -0.22.2 (grover) - Users can now manage their home directories, using the managehome - parameter, partially using patches provided by Tim Stoop and - Matt Palmer. (#432) - - Added 'ralsh' (formerly x2puppet) to the svn tree. When possible it - should be added to the packages. - - The 'notify' type now defaults to its message being the same as its name. - - Reopening $stdin to read from /dev/null during execution, in hopes that - init scripts will stop hanging. - - Changed the 'servername' fact set on the server to use the server's fqdn, - instead of the short-name. - - Changing the location of the configuration cache. It now defaults to being - in the state directory, rather than in the configuration directory. - - All parameter instances are stored in a single @parameters instance variable - hash within resource type instances. We used to use separate hashes for - each parameter type. - - Added the concept of provider features. Eventually these should be able - to express the full range of provider functionality, but for now they can - test a provider to see what methods it has set and determine what features it - provides as a result. These features are integrated into the doc generation - system so that you get feature documentation automatically. - - Switched apt/aptitide to using "apt-cache policy" instead of "apt-cache showpkg" - for determining the latest available version. (#487) - - FileBuckets now use a deeply nested structure for storing files, so - you do not end up with hundreds or thousands of files in the same - directory. (#447) - - Facts are now cached in the state file, and when they change the configuration - is always recompiled. (#519) - - Added 'ignoreimport' setting for use in commit hooks. This causes the - parser to ignore import statements so a single file can be parse-checked. (#544) - - Import statements can now specify multiple comma-separated arguments. - - Definitions now support both 'name' and 'title', just like any other - resource type. (#539) - - Added a generate() command, which sets values to the result of an external - command. (#541) - - Added a file() command to read in files with no interpolation. The first - found file has its content returned. - - puppetd now exits if no cert is present in onetime mode. (#533) - - The client configuration cache can be safely removed and the client - will correctly realize the client is not in sync. - - Resources can now be freely deleted, thus fixing many problems introduced - when deletion of required resources was forbidden when purging was introduced. - Only resources being purged will not be deleted. - - Facts and plugins now download even in noop mode (#540). - - Resources in noop mode now log when they would have responded to an event (#542). - - Refactored cron support entirely. Cron now uses providers, and there - is a single 'crontab' provider that handles user crontabs. While this - refactor does not include providers for /etc/crontab or cron.d, it should - now be straightforward to write those providers. - - Changed the parameter sorting so that the provider parameter comes - right after name, so the provider is available when the other parameters - and properties are being created. - - Redid some of the internals of the ParsedFile provider base class. - It now passes a FileRecord around instead of a hash. - - Fixing a bug related to link recursion that caused link directories - to always be considered out of sync. - - The bind address for puppetmasterd can now be specified with - --bindaddress. - - Added (probably experimental) mongrel support. At this point you're - still responsible for starting each individual process, and you have to - set up a proxy in front of it. - - Redesigned the 'network' tree to support multiple web servers, including - refactoring most of the structural code so it's much clearer and more - reusable now. - - Set up the CA client to default to ca_server and ca_port, so you can - easily run a separate CA. - - Supporting hosts with no domain name, thanks to a patch from - Dennis Jacobfeuerborn. - - Added an 'ignorecache' option to tell puppetd to force a recompile, thanks to - a patch by Chris McEniry. - - Made up2date the default for RHEL < 4 and yum the default for the rest. - - The yum provider now supports versions. - - Case statements correctly match when multiple values are provided, - thanks to a patch by David Schmitt. - - Functions can now be called with no arguments. - - String escapes parse correctly in all cases now, thanks to a patch by - cstorey. - - Subclasses again search parent classes for defaults. - - You can now purge apt and dpkg packages. - - When doing file recursion, 'ensure' only affects the top-level directory. - - States have been renamed to Properties. - -0.22.1 (kermit) -- Mostly a bugfix release - Compile times now persist between restarts of puppetd. - - Timeouts have been added to many parts of Puppet, reducing the likelihood - if it hanging forever on broken scripts or servers. - - All of the documentation and recipes have been moved to the wiki by Peter - Abrahamsen and Ben Kite has moved the FAQ to the wiki. - - Explicit relationships now override automatic relationships, allowing you - to manually specify deletion order when removing resources. - - Resources with dependencies can now be deleted as long as all of their - dependencies are also being deleted. - - Namespaces for both classes and definitions now work much more consistently. - You should now be able to specify a class or definition with a namespace - everywhere you would normally expect to be able to specify one without. - - Downcasing of facts can be selectively disabled. - - Cyclic dependency graphs are now checked for and forbidden. - - The netinfo mounts provider was commented out, because it really doesn't - work at all. Stupid NetInfo stores mount information with the device as - the key, which doesn't work with my current NetInfo code. - - Otherwise, lots and lots of bugfixes. Check the tickets associated with the - 'kermit' milestone. - -0.22.0 - Integrated the GRATR graph library into Puppet, for handling resource - relationships. - - Lots of bug-fixes (see bugs tickets associated with the 'minor' milestone). - - Added new 'resources' metatype, which currently only includes the ability - to purge unmanaged resources. - - Added better ability to generate new resource objects during transactions - (using 'generate' and 'eval_generate' methods). - - Rewrote all Rails support with a much better database design. Export/collect - now works, although the database is incompatible with previous versions. - - Removed downcasing of facts and made most of the language case-insensitive. - - Added support for printing the graphs built during transactions. - - Reworked how paths are built for logging. - - Switched all providers to directly executing commands instead of going through - a subshell, which removes the need to quote or escape arguments. - -0.20.1 - Mostly a bug-fix release, with the most important fix being the - multiple-definition error. - - Completely rewrote the ParsedFile system; each provider is now much - shorter and much more maintainable. However, fundamental problems - were found with the 'port' type, so it was disabled. Also, added - a NetInfo provider for 'host' and an experimental NetInfo provider - for 'mount'. - - Made the RRDGraph report *much* better and added reference - generation for reports and functions. - -0.20.0 - Significantly refactored the parser. Resource overrides now consistently - work anywhere in a class hierarchy. - - The language was also modified somewhat. The previous export/collect syntax - is now used for handling virtual objects, and export/collect (which is still - experimental) now uses double sigils (@@ and <<| |>>). - - Resource references (e.g., File["/etc/passwd"]) now have to be capitalized, - in fitting in with capitalizing type operations. - - As usual, lots of other smaller fixes, but most of the work was in the language. - -0.19.3 - Fixing a bug in server/master.rb that causes the hostname - not to be available in locally-executed manifests. - -0.19.2 - Fixing a few smaller bugs, notably in the reports system. - - Refreshed objects now generate an event, which can result in further - refreshes of other objects. - -0.19.1 - Fixing two critical bugs: User management works again and cron jobs are - no longer added to all user accounts. - -0.19.0 - Added provider support. - - Added support for %h, %H, and %d expansion in fileserver.conf. - - Added Certificate Revocation support. - - Made dynamic loading pervasive -- nearly every aspect of Puppet will now - automatically load new instances (e.g., types, providers, and reports). - - Added support for automatic distribution of facts and plugins (custom types). - -0.18.4 - Another bug-fix release. The most import bug fixed is that - cronjobs again work even with initially empty crontabs. - -0.18.3 - Mostly a bug-fix release; fixed small bugs in the functionality added in - 0.18.2. - -0.18.2 - Added templating support. - - Added reporting. - - Added gem and blastwave packaging support. - -0.18.1 - Added signal handlers for HUP, so both client and server deal correctly with it. - - Added signal handler for USR1, which triggers a run on the client. - - As usual, fixed many bugs. - - Significant fixes to puppetrun -- it should behave much more correctly now. - - Added "fail" function which throws a syntax error if it's encountered. - - Added plugin downloading from the central server to the client. It must be - enabled with --pluginsync. - - Added support for FreeBSD's special "@daily" cron schedules. - - Correctly handling spaces in file sources. - - Moved documentation into svn tree. - -0.18.0 - Added support for a "default" node. - - When multiple nodes are specified, they must now be comma-separated (this - introduces a language incompatibility). - - Failed dependencies cause dependent objects within the same transaction - not to run. - - Many updates to puppetrun - - Many bug fixes - - Function names are no longer reserved words. - - Links can now replace files. - -0.17.2 - Added "puppetrun" application and associated runner server and client classes. - - Fixed cron support so it better supports valid values and environment settings. - -0.17.1 - Fixing a bug requiring rails on all Debian boxes - - Fixing a couple of other small bugs - -0.17.0 - Adding ActiveRecord integration on the server - - Adding export/collect functionality - - Fixing many bugs - -0.16.5 - Fixing a critical bug in importing classes from other files - - Fixing nodename handling to actually allow dashes - -0.16.4 - Fixing a critical bug in puppetd when acquiring a certificate for the first - time - -0.16.3 - Some significant bug fixes - - Modified puppetd so that it can now function as an agent independent - of a puppetmasterd process, e.g., using the PuppetShow web application. - -0.16.2 - Modified some of the AST classes so that class names, definition names, and - node names are all set within the code being evaluated, so 'tagged(name)' returns - true while evaluating 'name', for instance. - - Added '--clean' argument to puppetca to remove all traces of a given - client. - -0.16.1 - Added 'tagged' and 'defined' functions. - - Moved all functions to a general framework that makes it very easy to add new - functions. - -0.16.0 - Added 'tag' keyword/function. - - Added FreeBSD Ports support - - Added 'pelement' server for sending or receiving Puppet objects, although - none of the executables use it yet. - -0.15.3 - Fixed many bugs in :exec, including adding support for arrays of checks - - Added autoloading for types and service variants (e.g., you can now - just create a new type in the appropriate location and use it in Puppet, - without modifying the core Puppet libs). - -0.15.2 - Added darwinport, Apple .pkg, and freebsd package types - Added 'mount type - Host facts are now set at the top scope (Bug #103) - Added -e (inline exection) flag to 'puppet' executable - Many small bug fixes - -0.15.1 - Fixed 'yum' installs so that they successfully upgrade packages. - Fixed puppetmasterd.conf file so group settings take. - -0.15.0 - Upped the minor release because the File server is incompatible with 0.14, - because it now handles links. - - The 'symlink' type is deprecated (but still present), in favor of using - files with the 'target' parameter. - - Unset variables no longer throw an error, they just return an empty string - - You can now specify tags to restrict which objects run during a given run. - - You can also specify to skip running against the cached copy when there's - a failure, which is useful for testing new configurations. - - RPMs and Sun packages can now install, as long as they specify a package - location, and they'll automatically upgrade if you point them to a new - file with an upgrade. - Multiple bug fixes. - - -0.14.1 - Fixed a couple of small logging bugs - Fixed a bug with handling group ownership of links - -0.14.0 - Added some ability to selectively manage symlinks when doing file management - Many bug fixes - Variables can now be used as the test values in case statements and selectors - Bumping a minor release number because 0.13.4 introduced a protocol - incompatibility and should have had a minor rev bump - -0.13.6 - Many, many small bug fixes - FreeBSD user/group support has been added - The configuration system has been rewritten so that daemons can now generate - and repair the files and directories they need. (Fixed bug #68.) - Fixed the element override issues; now only subclasses can override values. - -0.13.5 - Fixed packages so types can be specified - Added 'enable' state to services, although it does not work everywhere yet - -0.13.4 - A few important bug fixes, mostly in the parser. - -0.13.3 - Changed transactions to be one-stage instead of two - Changed all types to use self[:name] instead of self.name, to support - the symbolic naming implemented in 0.13.1 - -0.13.2 - Changed package[answerfile] to package[adminfile], and added package[responsefile] - Fixed a bunch of internal functions to behave more consistently and usefully - -0.13.1 - Fixed RPM spec files to create puppet user and group (lutter) - Fixed crontab reading and writing (luke) - Added symbolic naming in the language (luke) - -0.13.0 - Added support for configuration files. - Even more bug fixes, including the infamous 'frozen object' bug, which was a - problem with 'waitforcert'. - David Lutterkort got RPM into good shape. - -0.12.0 - Added Scheduling, and many bug fixes, of course. - -0.11.2 - Fixed bugs related to specifying arrays of requirements - Fixed a key bug in retrieving checksums - Fixed lots of usability bugs - Added 'fail' methods that automatically add file and line info when possible, - and converted many errors to use that method - -0.11.1 - Fixed bug with recursive copying with 'ignore' set. - Added OpenBSD package support. - -0.11.0 - Added 'ensure' state to many elements. - Modified puppetdoc to correctly handle indentation and such. - Significantly rewrote much of the builtin documentation to take advantage - of the new features in puppetdoc, including many examples. - -0.10.2 - Added SMF support - Added autorequire functionality, with specific support for exec and file - Exec elements autorequire any mentioned files, including the scripts, - along with their CWDs. - Files autorequire any parent directories. - Added 'alias' metaparam. - Fixed dependencies so they don't depend on file order. - -0.10.1 - Added Solaris package support and changed puppetmasterd to run as - a non-root user. - -0.10.0 - Significant refactoring of how types, states, and parameters work, including - breaking out parameters into a separate class. This refactoring did not - introduce much new functionality, but made extension of Puppet significantly - easier - - Also, fixed the bug with 'waitforcert' in puppetd. - -0.9.4 - Small fix to wrap the StatusServer class in the checks for required classes. - -0.9.3 - Fixed some significant bugs in cron job management. - -0.9.2 - Second Public Beta - -0.9.0 - First Public Beta diff --git a/COPYING b/COPYING deleted file mode 100644 index 3912109b5..000000000 --- a/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/LICENSE b/LICENSE index 6bfcc22a1..e95cc9fc1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,17 +1,17 @@ -Puppet - Automating Configuration Management. Copyright (C) 2005 Puppet Labs LLC + Puppet - Automating Configuration Management. -Puppet Labs can be contacted at: info@puppetlabs.com + Copyright (C) 2011 Puppet Labs Inc -This program and entire repository is free software; you can -redistribute it and/or modify it under the terms of the GNU -General Public License Version 2 as published by the Free Software -Foundation. + Puppet Labs can be contacted at: info@puppetlabs.com -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README b/README deleted file mode 100644 index d6b7d66bc..000000000 --- a/README +++ /dev/null @@ -1,31 +0,0 @@ -Documentation (and detailed install instructions) can be found -online at http://docs.puppetlabs.com/. - -Additional documentation can also be found at the Puppet Wiki: - -http://projects.puppetlabs.com/projects/puppet/wiki/ - -Generally, you need the following things installed: - -* Ruby >= 1.8.1 (earlier releases might work but probably not) - -* The Ruby OpenSSL library. For some reason, this often isn't included - in the main ruby distributions. You can test for it by running - 'ruby -ropenssl -e "puts :yep"'. If that errors out, you're missing the - library. - - If your distribution doesn't come with the necessary library (e.g., on Debian - and Ubuntu you need to install libopenssl-ruby), then you'll probably have to - compile Ruby yourself, since it's part of the standard library and not - available separately. You could probably just compile and install that one - library, though. - -* The Ruby XMLRPC client and server libraries. For some reason, this often - isn't included in the main ruby distributions. You can test for it by - running 'ruby -rxmlrpc/client -e "puts :yep"'. If that errors out, you're missing - the library. - -* Facter => 1.5.1 - You can get this from < http://puppetlabs.com/projects/facter > - -$Id$ diff --git a/README.rst b/README.md similarity index 57% rename from README.rst rename to README.md index 63452ef91..4d17a752a 100644 --- a/README.rst +++ b/README.md @@ -1,41 +1,40 @@ Puppet ====== Puppet, an automated administrative engine for your Linux and Unix systems, performs administrative tasks (such as adding users, installing packages, and updating server configurations) based on a centralized specification. -Documentation (and detailed install instructions) can be found online at the -`Puppet Documentation`_ site. - -Additional documentation can also be found at the `Puppet Wiki`_. +Documentation (and detailed installation instructions) can be found online at the +[Puppet Docs site](http://docs.puppetlabs.com). Installation ------------ Generally, you need the following things installed: * Ruby >= 1.8.1 (earlier releases might work but probably not) * The Ruby OpenSSL library. For some reason, this often isn't included in the main ruby distributions. You can test for it by running 'ruby -ropenssl -e "puts :yep"'. If that errors out, you're missing the library. If your distribution doesn't come with the necessary library (e.g., on Debian and Ubuntu you need to install libopenssl-ruby), then you'll probably have to compile Ruby yourself, since it's part of the standard library and not available separately. You could probably just compile and install that one library, though. -* The Ruby XMLRPC client and server libraries. For some reason, this often - isn't included in the main ruby distributions. You can test for it by - running 'ruby -rxmlrpc/client -e "puts :yep"'. If that errors out, you're missing - the library. +* Facter => 1.5.1 (available via your package manager or from the [Facter site](http://puppetlabs.com/projects/facter). + +License +------- + +See LICENSE file. + +Support +------- -* Facter => 1.5.1 - You can get this from your package management system or the `Facter site`_ +Please log tickets and issues at our [Projects site](http://projects.puppetlabs.com) -.. _Puppet Documentation: http://docs.puppetlabs.com -.. _Puppet Wiki: http://projects.puppetlabs.com/projects/puppet/wiki/ -.. _Facter site: http://puppetlabs.com/projects/facter diff --git a/README.queueing b/README.queueing deleted file mode 100644 index 83a8e19c0..000000000 --- a/README.queueing +++ /dev/null @@ -1,126 +0,0 @@ -*PUPPET QUEUEING - -Puppet Queueing is a feature which is designed to take some load -off of the PuppetMaster by transferring the task of updating the -database to a separate program which is named puppetqd (Puppet -Queue Daemon). - -Currently this is only supported for "Storeconfigs" which is -documented at: - -http://projects.puppetlabs.com/projects/1/wiki/Using_Stored_Configuration - -In the future this feature can be extended to any new puppet -data which involves storage in a database. - -*OPERATION - -In a nutshell: - - puppetmasterd -> stomp -> service -> stomp -> puppetqd -> database - -At the moment the only messaging protocol supported is "stomp". Although -others could be implemented, stomp is considered by many as the -default queueing mechanism for Ruby and Rails applications. It is -distributed as a Ruby gem and is easily installed. - -(The queueing code inside Puppet has been written so that when other -interfaces and protocols are implemented they will be easy to use by -changing settings in puppet.conf). - -The "service" in the diagram above is any queueing service that supports -the Stomp API. For details refer to: - - http://xircles.codehaus.org/projects/stomp - -Both puppetmasterd and puppetqd subscribe to the same queueing service -using the stomp interface. As puppetmasterd posts data to the queue, -puppetqd receives it and stores it. The details of how to connect to -the service and the name of the queue to use are set in puppet.conf: - - [main] - queue_type = stomp - queue_source = stomp://localhost:61613 - [puppetmasterd] - async_storeconfigs = true - -Note: since puppetmasterd needs to recover the data being stored at a -later time, both puppetmasterd and puppetqd need to work with the same -database as defined in the STORECONFIGS setup. - -*QUEUEING SERVICES - -As mentioned previously any queueing service that supports the Stomp -protocol can be used. Which one you use depends on your needs. We have -tested with two of the most popular services - StompServer and ActiveMQ. - -+ StompServer - - http://rubyforge.org/projects/stompserver/ - -StompServer is a lightweight queueing service written in Ruby which is -suitable for testing or low volume puppet usage. Works well when both -puppetmasterd and puppetd are running on the same machine that it's running -on but we encountered some problems when using it from multiple machines. - -Just install the stompserver gem and run 'stompserver'. - -+ Apache ActiveMQ - - http://activemq.apache.org - -Considered by many to be the most popular message service in use today, -ActiveMQ has hundreds of features for scaling, persistence and so on. - -Although installation is fairly simple, the configuration can seem quite -intimidating, but for our use a one line change to the standard configuration -is all that is required and is explained at: - - http://activemq.apache.org/stomp.html - -Other customization of the internal workings of ActiveMQ, if any, will depend -on your needs and deployment. A quick skimming of the ActiveMQ documentation -will give you enough info to decide. - -Others - -We have looked at but not tried some other queuing services which are -compatible with the Stomp API: - -+ POE Component Message Queue -+ JBoss Messaging (with 3rd party support for Stomp) - -*SCALING - -For StoreConfigs you basically need to have the catalog for a node stored -in the database before the next time the node connects and asks for a -new catalog. - -If the puppetd on your nodes is set to check every 30 minutes, -then it would seem that there is no problem. However if you have 3000 -nodes you have a LOT of catalogs to store and it is possible you will -not get a catalog saved in time. - -Running puppetmaster, your queueing service and puppetqd on the same -machine means that they are all competing for the same CPU cycles. Bumping -up the power of the server they are running on may be enough to handle -even fairly large deployments. - -However since most queueing services (even StompServer) are designed to -deliver messages from a "queue" to whoever asks for the next message you -can split things up between machines: - - puppetmaster1 --\ /-- puppetqd1 -\ - puppetmaster2 ----> ActiveMQ ---> puppetqd2 ---> database - puppetmaster3 --/ \-- puppetqd33 -/ - \- puppetqd4-/ - -This is, of course a totally contrived example, but it gets the point -across. As long as the data gets to the database, it doesn't matter -which machines or services it goes through. - -Although for StoreConfigs absolute reliability is not a requirement as -a new catalog will be sent the next time a node connects, some amount -of persistence should some process crash may be desirable. Both ActiveMQ -and MySQL (and other databases) have these kind of features built in -which can be activated as needed. diff --git a/conf/redhat/puppet.spec b/conf/redhat/puppet.spec index e51af0a6b..26b2c9ba0 100644 --- a/conf/redhat/puppet.spec +++ b/conf/redhat/puppet.spec @@ -1,454 +1,454 @@ # Augeas and SELinux requirements may be disabled at build time by passing # --without augeas and/or --without selinux to rpmbuild or mock %{!?ruby_sitelibdir: %global ruby_sitelibdir %(ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"]')} %global confdir conf/redhat Name: puppet Version: 2.6.0 Release: 1%{?dist} Summary: A network tool for managing many disparate systems -License: GPLv2+ +License: Apache 2.0 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 Group: System Environment/Base BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: facter >= 1.5 BuildRequires: ruby >= 1.8.1 %if 0%{?fedora} || 0%{?rhel} >= 5 BuildArch: noarch Requires: ruby(abi) = 1.8 Requires: ruby-shadow %endif # Pull in ruby selinux bindings where available %if 0%{?fedora} >= 12 || 0%{?rhel} >= 6 %{!?_without_selinux:Requires: ruby(selinux)} %else %if 0%{?fedora} || 0%{?rhel} >= 5 %{!?_without_selinux:Requires: libselinux-ruby} %endif %endif Requires: facter >= 1.5 Requires: ruby >= 1.8.1 %{!?_without_augeas:Requires: ruby-augeas} Requires(pre): shadow-utils Requires(post): chkconfig Requires(preun): chkconfig Requires(preun): initscripts Requires(postun): initscripts %description Puppet lets you centrally manage every important aspect of your system using a cross-platform specification language that manages all the separate elements normally aggregated in different files, like users, cron jobs, and hosts, along with obviously discrete elements like packages, services, and files. %package server Group: System Environment/Base Summary: Server for the puppet system management tool Requires: puppet = %{version}-%{release} Requires(post): chkconfig Requires(preun): chkconfig Requires(preun): initscripts Requires(postun): initscripts %description server Provides the central puppet server daemon which provides manifests to clients. The server can also function as a certificate authority and file server. %prep %setup -q patch -p1 < conf/redhat/rundir-perms.patch %build # Fix some rpmlint complaints for f in mac_dscl.pp mac_dscl_revert.pp \ mac_pkgdmg.pp ; do sed -i -e'1d' examples/$f chmod a-x examples/$f done for f in external/nagios.rb network/http_server/mongrel.rb relationship.rb; do sed -i -e '1d' lib/puppet/$f done chmod +x ext/puppetstoredconfigclean.rb find examples/ -type f -empty | xargs rm find examples/ -type f | xargs chmod a-x # puppet-queue.conf is more of an example, used for stompserver mv conf/puppet-queue.conf examples/etc/puppet/ %install rm -rf %{buildroot} ruby install.rb --destdir=%{buildroot} --quick --no-rdoc install -d -m0755 %{buildroot}%{_sysconfdir}/puppet/manifests install -d -m0755 %{buildroot}%{_datadir}/%{name}/modules install -d -m0755 %{buildroot}%{_localstatedir}/lib/puppet install -d -m0755 %{buildroot}%{_localstatedir}/run/puppet install -d -m0750 %{buildroot}%{_localstatedir}/log/puppet install -Dp -m0644 %{confdir}/client.sysconfig %{buildroot}%{_sysconfdir}/sysconfig/puppet install -Dp -m0755 %{confdir}/client.init %{buildroot}%{_initrddir}/puppet install -Dp -m0644 %{confdir}/server.sysconfig %{buildroot}%{_sysconfdir}/sysconfig/puppetmaster install -Dp -m0755 %{confdir}/server.init %{buildroot}%{_initrddir}/puppetmaster install -Dp -m0644 %{confdir}/fileserver.conf %{buildroot}%{_sysconfdir}/puppet/fileserver.conf install -Dp -m0644 %{confdir}/puppet.conf %{buildroot}%{_sysconfdir}/puppet/puppet.conf install -Dp -m0644 conf/auth.conf %{buildroot}%{_sysconfdir}/puppet/auth.conf install -Dp -m0644 %{confdir}/logrotate %{buildroot}%{_sysconfdir}/logrotate.d/puppet # We need something for these ghosted files, otherwise rpmbuild # will complain loudly. They won't be included in the binary packages touch %{buildroot}%{_sysconfdir}/puppet/puppetmasterd.conf touch %{buildroot}%{_sysconfdir}/puppet/puppetca.conf touch %{buildroot}%{_sysconfdir}/puppet/puppetd.conf # Install the ext/ directory to %{_datadir}/%{name} install -d %{buildroot}%{_datadir}/%{name} cp -a ext/ %{buildroot}%{_datadir}/%{name} # emacs and vim bits are installed elsewhere rm -rf %{buildroot}%{_datadir}/%{name}/ext/{emacs,vim} # Install emacs mode files emacsdir=%{buildroot}%{_datadir}/emacs/site-lisp install -Dp -m0644 ext/emacs/puppet-mode.el $emacsdir/puppet-mode.el install -Dp -m0644 ext/emacs/puppet-mode-init.el \ $emacsdir/site-start.d/puppet-mode-init.el # Install vim syntax files vimdir=%{buildroot}%{_datadir}/vim/vimfiles install -Dp -m0644 ext/vim/ftdetect/puppet.vim $vimdir/ftdetect/puppet.vim install -Dp -m0644 ext/vim/syntax/puppet.vim $vimdir/syntax/puppet.vim %files %defattr(-, root, root, 0755) %doc CHANGELOG COPYING LICENSE README README.queueing examples %{_bindir}/pi %{_bindir}/puppet %{_bindir}/ralsh %{_bindir}/filebucket %{_bindir}/puppetdoc %{_sbindir}/puppetca %{_sbindir}/puppetd %{ruby_sitelibdir}/* %{_initrddir}/puppet %dir %{_sysconfdir}/puppet %config(noreplace) %{_sysconfdir}/sysconfig/puppet %config(noreplace) %{_sysconfdir}/puppet/puppet.conf %config(noreplace) %{_sysconfdir}/puppet/auth.conf %ghost %config(noreplace,missingok) %{_sysconfdir}/puppet/puppetca.conf %ghost %config(noreplace,missingok) %{_sysconfdir}/puppet/puppetd.conf %config(noreplace) %{_sysconfdir}/logrotate.d/puppet # We don't want to require emacs or vim, so we need to own these dirs %{_datadir}/emacs %{_datadir}/vim %{_datadir}/%{name} # These need to be owned by puppet so the server can # write to them %attr(-, puppet, puppet) %{_localstatedir}/run/puppet %attr(-, puppet, puppet) %{_localstatedir}/log/puppet %attr(-, puppet, puppet) %{_localstatedir}/lib/puppet %{_mandir}/man5/puppet.conf.5.gz %{_mandir}/man8/pi.8.gz %{_mandir}/man8/puppet.8.gz %{_mandir}/man8/puppetca.8.gz %{_mandir}/man8/puppetd.8.gz %{_mandir}/man8/ralsh.8.gz %{_mandir}/man8/puppetdoc.8.gz %files server %defattr(-, root, root, 0755) %{_sbindir}/puppetmasterd %{_sbindir}/puppetrun %{_sbindir}/puppetqd %{_initrddir}/puppetmaster %config(noreplace) %{_sysconfdir}/puppet/fileserver.conf %dir %{_sysconfdir}/puppet/manifests %config(noreplace) %{_sysconfdir}/sysconfig/puppetmaster %ghost %config(noreplace,missingok) %{_sysconfdir}/puppet/puppetmasterd.conf %{_mandir}/man8/filebucket.8.gz %{_mandir}/man8/puppetmasterd.8.gz %{_mandir}/man8/puppetrun.8.gz %{_mandir}/man8/puppetqd.8.gz # Fixed uid/gid were assigned in bz 472073 (Fedora), 471918 (RHEL-5), # and 471919 (RHEL-4) %pre getent group puppet &>/dev/null || groupadd -r puppet -g 52 &>/dev/null getent passwd puppet &>/dev/null || \ useradd -r -u 52 -g puppet -d %{_localstatedir}/lib/puppet -s /sbin/nologin \ -c "Puppet" puppet &>/dev/null || : # ensure that old setups have the right puppet home dir if [ $1 -gt 1 ] ; then usermod -d %{_localstatedir}/lib/puppet puppet &>/dev/null || : fi %post /sbin/chkconfig --add puppet || : %post server /sbin/chkconfig --add puppetmaster || : %preun if [ "$1" = 0 ] ; then /sbin/service puppet stop > /dev/null 2>&1 /sbin/chkconfig --del puppet || : fi %preun server if [ "$1" = 0 ] ; then /sbin/service puppetmaster stop > /dev/null 2>&1 /sbin/chkconfig --del puppetmaster || : fi %postun if [ "$1" -ge 1 ]; then /sbin/service puppet condrestart >/dev/null 2>&1 || : fi %postun server if [ "$1" -ge 1 ]; then /sbin/service puppetmaster condrestart > /dev/null 2>&1 || : fi %clean rm -rf %{buildroot} %changelog * Tue Jul 20 2010 Todd Zullinger - 2.6.0-1 - Update to 2.6.0 - Create and own /usr/share/puppet/modules (#615432) * Mon May 03 2010 Todd Zullinger - 0.25.5-1 - Update to 0.25.5 - Adjust selinux conditional for EL-6 - Apply rundir-perms patch from tarball rather than including it separately * Fri Jan 01 2010 Todd Zullinger - 0.25.2-1 - Update to 0.25.2 - Install auth.conf, puppetqd manpage, and queuing examples/docs * Tue Oct 20 2009 Todd Zullinger - 0.25.1-1 - Update to 0.25.1 - Include the pi program and man page (R.I.Pienaar) * Sat Oct 17 2009 Todd Zullinger - 0.25.1-0.2.rc2 - Update to 0.25.1rc2 * Tue Sep 22 2009 Todd Zullinger - 0.25.1-0.1.rc1 - Update to 0.25.1rc1 - Move puppetca to puppet package, it has uses on client systems - Drop redundant %%doc from manpage %%file listings * Fri Sep 04 2009 Todd Zullinger - 0.25.0-1 - Update to 0.25.0 - Fix permissions on /var/log/puppet (#495096) - Install emacs mode and vim syntax files (#491437) - Install ext/ directory in %%{_datadir}/%{name} (/usr/share/puppet) * Mon May 04 2009 Todd Zullinger - 0.25.0-0.1.beta1 - Update to 0.25.0beta1 - Make Augeas and SELinux requirements build time options * Mon Mar 23 2009 Todd Zullinger - 0.24.8-1 - Update to 0.24.8 - Quiet output from %%pre - Use upstream install script - Increase required facter version to >= 1.5 * Tue Dec 16 2008 Todd Zullinger - 0.24.7-4 - Remove redundant useradd from %%pre * Tue Dec 16 2008 Jeroen van Meeuwen - 0.24.7-3 - New upstream version - Set a static uid and gid (#472073, #471918, #471919) - Add a conditional requirement on libselinux-ruby for Fedora >= 9 - Add a dependency on ruby-augeas * Wed Oct 22 2008 Todd Zullinger - 0.24.6-1 - Update to 0.24.6 - Require ruby-shadow on Fedora and RHEL >= 5 - Simplify Fedora/RHEL version checks for ruby(abi) and BuildArch - Require chkconfig and initstripts for preun, post, and postun scripts - Conditionally restart puppet in %%postun - Ensure %%preun, %%post, and %%postun scripts exit cleanly - Create puppet user/group according to Fedora packaging guidelines - Quiet a few rpmlint complaints - Remove useless %%pbuild macro - Make specfile more like the Fedora/EPEL template * Mon Jul 28 2008 David Lutterkort - 0.24.5-1 - Add /usr/bin/puppetdoc * Thu Jul 24 2008 Brenton Leanhardt - New version - man pages now ship with tarball - examples/code moved to root examples dir in upstream tarball * Tue Mar 25 2008 David Lutterkort - 0.24.4-1 - Add man pages (from separate tarball, upstream will fix to include in main tarball) * Mon Mar 24 2008 David Lutterkort - 0.24.3-1 - New version * Wed Mar 5 2008 David Lutterkort - 0.24.2-1 - New version * Sat Dec 22 2007 David Lutterkort - 0.24.1-1 - New version * Mon Dec 17 2007 David Lutterkort - 0.24.0-2 - Use updated upstream tarball that contains yumhelper.py * Fri Dec 14 2007 David Lutterkort - 0.24.0-1 - Fixed license - Munge examples/ to make rpmlint happier * Wed Aug 22 2007 David Lutterkort - 0.23.2-1 - New version * Thu Jul 26 2007 David Lutterkort - 0.23.1-1 - Remove old config files * Wed Jun 20 2007 David Lutterkort - 0.23.0-1 - Install one puppet.conf instead of old config files, keep old configs around to ease update - Use plain shell commands in install instead of macros * Wed May 2 2007 David Lutterkort - 0.22.4-1 - New version * Thu Mar 29 2007 David Lutterkort - 0.22.3-1 - Claim ownership of _sysconfdir/puppet (bz 233908) * Mon Mar 19 2007 David Lutterkort - 0.22.2-1 - Set puppet's homedir to /var/lib/puppet, not /var/puppet - Remove no-lockdir patch, not needed anymore * Mon Feb 12 2007 David Lutterkort - 0.22.1-2 - Fix bogus config parameter in puppetd.conf * Sat Feb 3 2007 David Lutterkort - 0.22.1-1 - New version * Fri Jan 5 2007 David Lutterkort - 0.22.0-1 - New version * Mon Nov 20 2006 David Lutterkort - 0.20.1-2 - Make require ruby(abi) and buildarch: noarch conditional for fedora 5 or later to allow building on older fedora releases * Mon Nov 13 2006 David Lutterkort - 0.20.1-1 - New version * Mon Oct 23 2006 David Lutterkort - 0.20.0-1 - New version * Tue Sep 26 2006 David Lutterkort - 0.19.3-1 - New version * Mon Sep 18 2006 David Lutterkort - 0.19.1-1 - New version * Thu Sep 7 2006 David Lutterkort - 0.19.0-1 - New version * Tue Aug 1 2006 David Lutterkort - 0.18.4-2 - Use /usr/bin/ruby directly instead of /usr/bin/env ruby in executables. Otherwise, initscripts break since pidof can't find the right process * Tue Aug 1 2006 David Lutterkort - 0.18.4-1 - New version * Fri Jul 14 2006 David Lutterkort - 0.18.3-1 - New version * Wed Jul 5 2006 David Lutterkort - 0.18.2-1 - New version * Wed Jun 28 2006 David Lutterkort - 0.18.1-1 - Removed lsb-config.patch and yumrepo.patch since they are upstream now * Mon Jun 19 2006 David Lutterkort - 0.18.0-1 - Patch config for LSB compliance (lsb-config.patch) - Changed config moves /var/puppet to /var/lib/puppet, /etc/puppet/ssl to /var/lib/puppet, /etc/puppet/clases.txt to /var/lib/puppet/classes.txt, /etc/puppet/localconfig.yaml to /var/lib/puppet/localconfig.yaml * Fri May 19 2006 David Lutterkort - 0.17.2-1 - Added /usr/bin/puppetrun to server subpackage - Backported patch for yumrepo type (yumrepo.patch) * Wed May 3 2006 David Lutterkort - 0.16.4-1 - Rebuilt * Fri Apr 21 2006 David Lutterkort - 0.16.0-1 - Fix default file permissions in server subpackage - Run puppetmaster as user puppet - rebuilt for 0.16.0 * Mon Apr 17 2006 David Lutterkort - 0.15.3-2 - Don't create empty log files in post-install scriptlet * Fri Apr 7 2006 David Lutterkort - 0.15.3-1 - Rebuilt for new version * Wed Mar 22 2006 David Lutterkort - 0.15.1-1 - Patch0: Run puppetmaster as root; running as puppet is not ready for primetime * Mon Mar 13 2006 David Lutterkort - 0.15.0-1 - Commented out noarch; requires fix for bz184199 * Mon Mar 6 2006 David Lutterkort - 0.14.0-1 - Added BuildRequires for ruby * Wed Mar 1 2006 David Lutterkort - 0.13.5-1 - Removed use of fedora-usermgmt. It is not required for Fedora Extras and makes it unnecessarily hard to use this rpm outside of Fedora. Just allocate the puppet uid/gid dynamically * Sun Feb 19 2006 David Lutterkort - 0.13.0-4 - Use fedora-usermgmt to create puppet user/group. Use uid/gid 24. Fixed problem with listing fileserver.conf and puppetmaster.conf twice * Wed Feb 8 2006 David Lutterkort - 0.13.0-3 - Fix puppetd.conf * Wed Feb 8 2006 David Lutterkort - 0.13.0-2 - Changes to run puppetmaster as user puppet * Mon Feb 6 2006 David Lutterkort - 0.13.0-1 - Don't mark initscripts as config files * Mon Feb 6 2006 David Lutterkort - 0.12.0-2 - Fix BuildRoot. Add dist to release * Tue Jan 17 2006 David Lutterkort - 0.11.0-1 - Rebuild * Thu Jan 12 2006 David Lutterkort - 0.10.2-1 - Updated for 0.10.2 Fixed minor kink in how Source is given * Wed Jan 11 2006 David Lutterkort - 0.10.1-3 - Added basic fileserver.conf * Wed Jan 11 2006 David Lutterkort - 0.10.1-1 - Updated. Moved installation of library files to sitelibdir. Pulled initscripts into separate files. Folded tools rpm into server * Thu Nov 24 2005 Duane Griffin - Added init scripts for the client * Wed Nov 23 2005 Duane Griffin - First packaging diff --git a/conf/solaris/pkginfo b/conf/solaris/pkginfo index 7f7bb9736..14a2f0a79 100644 --- a/conf/solaris/pkginfo +++ b/conf/solaris/pkginfo @@ -1,7 +1,6 @@ PKG=CSWpuppet NAME=puppet - System Automation Framework -VERSION=0.23.0 +VERSION=2.7.0 CATEGORY=application -VENDOR=http://reductivelabs.com/projects/puppet -HOTLINE=http://reductivelabs.com/cgi-bin/puppet.cgi -EMAIL=luke@madstop.com +VENDOR=http://projects.puppetlabs.com/projects/puppet +EMAIL=luke@puppetlabs.com diff --git a/conf/suse/puppet.spec b/conf/suse/puppet.spec index 777f6a4b6..2a5b9f4db 100644 --- a/conf/suse/puppet.spec +++ b/conf/suse/puppet.spec @@ -1,297 +1,297 @@ %{!?ruby_sitelibdir: %define ruby_sitelibdir %(ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"]')} %define pbuild %{_builddir}/%{name}-%{version} %define confdir conf/suse Summary: A network tool for managing many disparate systems Name: puppet Version: 2.6.1 Release: 1%{?dist} -License: GPL +License: Apache 2.0 Group: Productivity/Networking/System 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.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, along with obviously discrete elements like packages, services, and files. %package server Group: Productivity/Networking/System Summary: Server for the puppet system management tool Requires: puppet = %{version}-%{release} %description server Provides the central puppet server daemon which provides manifests to clients. The server can also function as a certificate authority and file server. %prep %setup -q %build 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}%{_bindir} %{__install} -Dp -m0755 %{pbuild}/sbin/* %{buildroot}%{_sbindir} %{__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 '{}' \; %{__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 %{_bindir}/puppetdoc %{_bindir}/filebucket %{_bindir}/ralsh %{_bindir}/pi %{_sbindir}/puppetd %{_sbindir}/rcpuppet %{ruby_sitelibdir}/* %{_initrddir}/puppet /var/adm/fillup-templates/sysconfig.puppet %config(noreplace) %{_sysconfdir}/puppet/puppet.conf %doc CHANGELOG COPYING LICENSE README examples %config(noreplace) %{_sysconfdir}/logrotate.d/puppet %dir %{_sysconfdir}/puppet # These need to be owned by puppet so the server can # write to them %attr(-, puppet, puppet) %{_localstatedir}/run/puppet %attr(-, puppet, puppet) %{_localstatedir}/log/puppet %attr(-, puppet, puppet) %{_localstatedir}/lib/puppet %files server %defattr(-, root, root, 0755) %{_sbindir}/puppetmasterd %{_sbindir}/rcpuppetmaster %{_sbindir}/puppetqd %{_sbindir}/puppetrun %{_sbindir}/puppetca %{_initrddir}/puppetmaster %config(noreplace) %{_sysconfdir}/puppet/* %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/puppet puppet 2> /dev/null || : %post %{fillup_and_insserv -y puppet} %post server %{fillup_and_insserv -n -y puppetmaster} %preun %stop_on_removal puppet %preun server %stop_on_removal puppetmaster %postun %restart_on_update puppet %{insserv_cleanup} %postun server %restart_on_update puppetmaster %{insserv_cleanup} %clean %{__rm} -rf %{buildroot} %changelog * Tue Sep 14 2010 Ben Kevan - 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 - 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 - 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 - 0.25.4 - New version. * Sun Aug 9 2009 Noah Fontes - Fix build on SLES 9. - Enable puppet and puppet-server services by default. * Sat Aug 8 2009 Noah Fontes - 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 - 0.24.8 - New version. * Tue Dec 9 2008 Leo Eraly - 0.24.6 - New version. * Fri Sep 5 2008 Leo Eraly - 0.24.5 - New version. * Fri Jun 20 2008 Martin Vuk - 0.24.4 - Removed symlinks to old configuration files * Fri Dec 14 2007 Martin Vuk - 0.24.0 - New version. * Fri Jun 29 2007 Martin Vuk - 0.23.0 - New version. * Wed May 2 2007 Martin Vuk - 0.22.4 - New version. Includes provider for rug package manager. * Wed Apr 25 2007 Martin Vuk - 0.22.3 - New version. Added links /sbin/rcpuppet and /sbin/rcpuppetmaster * Sun Jan 7 2007 Martin Vuk - 0.22.0 - version bump * Tue Oct 3 2006 Martin Vuk - 0.19.3-3 - Made package arch dependant. * Sat Sep 23 2006 Martin Vuk - 0.19.3-1 - New version * Sun Sep 17 2006 Martin Vuk - 0.19.1-1 - New version * Tue Aug 30 2006 Martin Vuk - 0.19.0-1 - New version - No need to patch anymore :-), since my changes went into official release. * Tue Aug 3 2006 Martin Vuk - 0.18.4-3 - Replaced puppet-bin.patch with %build section from David's spec * Tue Aug 1 2006 Martin Vuk - 0.18.4-2 - Added supprot for enabling services in SuSE * Tue Aug 1 2006 Martin Vuk - 0.18.4-1 - New version and support for SuSE * Wed Jul 5 2006 David Lutterkort - 0.18.2-1 - New version * Wed Jun 28 2006 David Lutterkort - 0.18.1-1 - Removed lsb-config.patch and yumrepo.patch since they are upstream now * Mon Jun 19 2006 David Lutterkort - 0.18.0-1 - Patch config for LSB compliance (lsb-config.patch) - Changed config moves /var/puppet to /var/lib/puppet, /etc/puppet/ssl to /var/lib/puppet, /etc/puppet/clases.txt to /var/lib/puppet/classes.txt, /etc/puppet/localconfig.yaml to /var/lib/puppet/localconfig.yaml * Fri May 19 2006 David Lutterkort - 0.17.2-1 - Added /usr/bin/puppetrun to server subpackage - Backported patch for yumrepo type (yumrepo.patch) * Wed May 3 2006 David Lutterkort - 0.16.4-1 - Rebuilt * Fri Apr 21 2006 David Lutterkort - 0.16.0-1 - Fix default file permissions in server subpackage - Run puppetmaster as user puppet - rebuilt for 0.16.0 * Mon Apr 17 2006 David Lutterkort - 0.15.3-2 - Don't create empty log files in post-install scriptlet * Fri Apr 7 2006 David Lutterkort - 0.15.3-1 - Rebuilt for new version * Wed Mar 22 2006 David Lutterkort - 0.15.1-1 - Patch0: Run puppetmaster as root; running as puppet is not ready for primetime * Mon Mar 13 2006 David Lutterkort - 0.15.0-1 - Commented out noarch; requires fix for bz184199 * Mon Mar 6 2006 David Lutterkort - 0.14.0-1 - Added BuildRequires for ruby * Wed Mar 1 2006 David Lutterkort - 0.13.5-1 - Removed use of fedora-usermgmt. It is not required for Fedora Extras and makes it unnecessarily hard to use this rpm outside of Fedora. Just allocate the puppet uid/gid dynamically * Sun Feb 19 2006 David Lutterkort - 0.13.0-4 - Use fedora-usermgmt to create puppet user/group. Use uid/gid 24. Fixed problem with listing fileserver.conf and puppetmaster.conf twice * Wed Feb 8 2006 David Lutterkort - 0.13.0-3 - Fix puppetd.conf * Wed Feb 8 2006 David Lutterkort - 0.13.0-2 - Changes to run puppetmaster as user puppet * Mon Feb 6 2006 David Lutterkort - 0.13.0-1 - Don't mark initscripts as config files * Mon Feb 6 2006 David Lutterkort - 0.12.0-2 - Fix BuildRoot. Add dist to release * Tue Jan 17 2006 David Lutterkort - 0.11.0-1 - Rebuild * Thu Jan 12 2006 David Lutterkort - 0.10.2-1 - Updated for 0.10.2 Fixed minor kink in how Source is given * Wed Jan 11 2006 David Lutterkort - 0.10.1-3 - Added basic fileserver.conf * Wed Jan 11 2006 David Lutterkort - 0.10.1-1 - Updated. Moved installation of library files to sitelibdir. Pulled initscripts into separate files. Folded tools rpm into server * Thu Nov 24 2005 Duane Griffin - Added init scripts for the client * Wed Nov 23 2005 Duane Griffin - First packaging diff --git a/ext/nagios/naggen b/ext/nagios/naggen index c6ca15a55..16dbe6ce4 100755 --- a/ext/nagios/naggen +++ b/ext/nagios/naggen @@ -1,302 +1,309 @@ #!/usr/bin/env ruby # # = Synopsis # # Generate Nagios configurations from Puppet Resources in an ActiveRecord database # # = Usage # # naggen [-h|--help] [-d|--debug] [-v|--verbose] [--compare] # # = Description # # This executable is a means of short-circuiting the process of generating nagios # configurations on your server using Puppet Exported Resources. It skips any possible # naming conflicts resulting from Puppet's resource uniqueness requirements, and it # also skips the inefficiencies involved in converting and transporting large numbers # of Puppet resources. # # At the least, the machine that runs this will need ActiveRecord (2.0.2) installed, # along with any database libraries you use. # # = Options # # Note that any configuration parameter that's valid in the configuration file # is also a valid long argument. For example, 'ssldir' is a valid configuration # parameter, so you can specify '--ssldir ' as an argument. # # You can add naggen-specific settings to your puppet.conf in a '[naggen]' section, # just like any other executable. # # 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 with # '--genconfig'. # # compare:: # Compare new and old files and only backup and write if the files are different. # Potentially expensive computationally, but idempotent. Will exit with 0 if # no changes were made and 1 if there were. # # debug:: # Enable full debugging. # # detailed-exitcodes:: # Provide transaction information via exit codes. If 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. # # help:: # Print this help message # # verbose:: # Print extra information. # # = Example # # naggen --storeconfigs --confdir /foo --compare # -# = Author # -# Luke Kanies +# = License +# Copyright 2011 Luke Kanies # -# = Copyright +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# Copyright (c) 2009 Puppet Labs, LLC -# Licensed under the GPL 2 +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. require 'puppet' require 'puppet/rails' require 'puppet/rails/resource' require 'puppet/rails/param_value' require 'puppet/network/client' require 'puppet/parser/collector' require 'puppet/provider/naginator' require 'getoptlong' # Monkey-patch the rails resources so we can # easily convert them to nagios instances. class Puppet::Rails::Resource def to_param_hash values = @params_hash || Puppet::Rails::ParamValue.find_all_params_from_resource(self) if values.size == 0 return {} end values.inject({}) do |hash, value| hash[value['name']] ||= [] hash[value['name']] << value["value"] hash end end def to_nagios unless nagios_type = Nagios::Base.type(restype.sub("Nagios_", '').to_sym) raise Puppet::DevError, "Could not find nagios type '%s'" % restype end result = nagios_type.new to_param_hash.each do |param, value| next unless nagios_type.parameter?(param) result[param] = value end result[:name] = self.title result end end class NagiosWriter class FakeScope def debug(string) Puppet.debug string end def host "this host doesn't exist" end end attr_accessor :nagios_type, :bucket def backup(target) return unless FileTest.exist?(target) and File.stat(target).size > 0 Puppet.info "Backing up %s" % target bucket.backup(target) end def collector collector = Puppet::Parser::Collector.new(FakeScope.new, "nagios_" + @nagios_type.to_s, nil, nil, :exported) # We don't have a scope, so we're stubbing everything out that would interact # with the scope. class << collector def collect_virtual(*args) [] end def exported_resource(res) res end end collector end def default_target "/etc/nagios/nagios_#{nagios_type.to_s}.cfg" end def evaluate return unless resources = rails_resources() resources_by_target = resources.inject({}) do |hash, resource| target = resource["target"] || default_target hash[target] ||= [] hash[target] << resource hash end changed = false resources_by_target.each do |target, resources| begin result = write(target, resources) rescue => detail $stderr.puts detail.backtrace Puppet.err "Could not write to %s: %s" % [target, detail] end changed = true if result end changed end def initialize(nagios_type) @nagios_type = nagios_type @bucket = Puppet::FileBucket::Dipper.new(:Path => Puppet[:clientbucketdir]) end def rails_resources collector.send(:collect_exported) end def write(target, resources) # Skip the nagios type when we have no resources and no existing # file. return if resources.empty? and ! FileTest.exist?(target) dir = File.dirname(target) unless FileTest.exist?(dir) FileUtils.mkdir_p(dir) end count = 0 tempfile = target + ".tmp" File.open(tempfile, "w") do |file| resources.each do |resource| count += 1 file.puts resource.to_nagios.to_s.gsub("_naginator_name", Puppet::Provider::Naginator::NAME_STRING) end end if $options[:compare] if FileTest.exist?(target) and File.read(tempfile) == File.read(target) return false end end backup(target) # Atomic rename File.rename(tempfile, target) Puppet.notice "Wrote %s resources to %s" % [count, target] return true ensure File.unlink(tempfile) if tempfile and FileTest.exist?(tempfile) end end arguments = [ [ "--compare", "-c", GetoptLong::NO_ARGUMENT ], [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ] ] Puppet.settings.addargs(arguments) result = GetoptLong.new(*arguments) $options = {} result.each { |opt,arg| case opt when "--help" begin require 'rdoc/usage' RDoc::usage && exit rescue LoadError docs = [] File.readlines(__FILE__).each do |line| next if line =~ /^#\!/ unless line =~ /^#/ next if docs.length == 0 # skip the first line or so break # else, we've passed the docs, so just break end docs << line.sub(/^# ?/, '') end print docs exit end when "--compare" $options[:compare] = true when "--verbose" $options[:verbose] = true when "--debug" $options[:debug] = true when "--debug" $options[:debug] = true else Puppet.settings.handlearg(opt, arg) end } # Read in Puppet settings, so we know how Puppet's configured. Puppet.parse_config Puppet::Util::Log.newdestination(:console) if $options[:debug] Puppet::Util::Log.level = :debug elsif $options[:verbose] Puppet::Util::Log.level = :info end # See if Naginator is installed directly, else load Puppet's version. begin require 'nagios' rescue LoadError require 'puppet/external/nagios' end changed = false Nagios::Base.eachtype do |name, type| writer = NagiosWriter.new(name) changed = true if writer.evaluate end if $options[:compare] and changed exit(1) else exit(0) end diff --git a/ext/puppet-test b/ext/puppet-test index f2648c9ee..affb01249 100755 --- a/ext/puppet-test +++ b/ext/puppet-test @@ -1,560 +1,566 @@ #!/usr/bin/env ruby # == Synopsis # # Test individual client performance. Can compile configurations, describe # files, or retrieve files. # # = Usage # # puppet-test [-c|--compile] [-D|--describe ] [-d|--debug] # [--fork ] [-h|--help] [-H|--hostname ] [-l|--list] [-r|--repeat ] # [-R|--retrieve ] [-t|--test ] [-V|--version] [-v|--verbose] # # = Description # # This is a simple script meant for doing performance tests with Puppet. By # default it pulls down a compiled configuration, but it supports multiple # other tests. # # = Options # # 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 ' as an argument. # # 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 puppetd with # '--genconfig'. # # compile:: # Compile the client's configuration. The default. # # debug:: # Enable full debugging. # # describe:: # Describe the file being tested. This is a query to get information about # the file from the server, to determine if it should be copied, and is the # first half of every file transfer. # # fork:: # Fork the specified number of times, thus acting as multiple clients. # # 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. # # help:: # Print this help message # # list:: # List all available tests. # # node:: # Specify the node to use. This is useful for looking up cached yaml data # in your :clientyaml directory, and forcing a specific host's configuration to # get compiled. # # pause:: # Pause before starting test (useful for testing with dtrace). # # repeat:: # How many times to perform the test. # # retrieve:: # Test file retrieval performance. Retrieves the specified file from the # remote system. Note that the server should be specified via --server, # so the argument to this option is just the remote module name and path, # e.g., "/dist/apps/myapp/myfile", where "dist" is the module and # "apps/myapp/myfile" is the path to the file relative to the module. # # test:: # Specify the test to run. You can see the list of tests by running this command with --list. # # verbose:: # Turn on verbose reporting. # # version:: # Print the puppet version number and exit. # # = Example # # puppet-test --retrieve /module/path/to/file # -# = Author +# = License +# Copyright 2011 Luke Kanies # -# Luke Kanies +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# = Copyright +# http://www.apache.org/licenses/LICENSE-2.0 # -# Copyright (c) 2005, 2006 Puppet Labs, LLC -# Licensed under the GNU Public License +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # Do an initial trap, so that cancels don't get a stack trace. trap(:INT) do $stderr.puts "Cancelling startup" exit(1) end require 'puppet' require 'puppet/network/client' require 'getoptlong' class Suite attr_reader :name, :doc @@suites = {} @@tests = {} def self.[](name) @@suites[name] end # Run a test by first finding the suite then running the appropriate test. def self.run(test) unless suite_name = @@tests[test] raise "Unknown test %s" % test end unless suite = @@suites[suite_name] raise "Unknown test suite %s from test %s" % [suite_name, test] end suite.run(test) end # What suites are available? def self.suites @@suites.keys end def forked? defined? @forking end # Create a new test suite. def initialize(name, doc, &block) @name = name @doc = doc @tests = {} @@suites[name] = self raise "You must pass a block to the Test" unless block_given? instance_eval(&block) end # Define a new type of test on this suite. def newtest(name, doc, &block) @tests[name] = doc if @@tests[name] raise "Test names must be unique; cannot redefine %s" % name end @@tests[name] = @name meta_def(name, &block) end # Run the actual test. def run(test) unless doc = @tests[test] raise "Suite %s only supports tests %s; not %s" % [@name, @tests.keys.collect { |k| k.to_s }.join(","), test] end puts "Running %s %s test" % [@name, test] prepare() if respond_to?(:prepare) if $options[:pause] puts "Hit any key to continue" $stdin.readline puts "Continuing with test" end if $options[:fork] > 0 @forking = true $options[:fork].times { if pid = fork $pids << pid else break end } end $options[:repeat].times do |i| @count = i if forked? msg = doc + " in PID %s" % Process.pid else msg = doc end Puppet::Util.benchmark(:notice, msg) do begin send(test) rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "%s failed: %s" % [@name, detail.to_s] end end end end # What tests are available on this suite? def tests @tests.keys end end Suite.new :parser, "Manifest parsing" do newtest :parse, "Parsed files" do @parser = Puppet::Parser::Parser.new(:environment => Puppet[:environment]) @parser.file = Puppet[:manifest] @parser.parse end end Suite.new :local_catalog, "Local catalog handling" do def prepare @node = Puppet::Node.find($options[:nodes][0]) end newtest :compile, "Compiled catalog" do Puppet::Resource::Catalog.find(@node) end end Suite.new :resource_type, "Managing resource types" do newtest :find, "Find a type" do Puppet::Resource::Type.terminus_class = :parser ARGV.each do |name| json = Puppet::Resource::Type.find(name).to_pson data = PSON.parse(json) p Puppet::Resource::Type.from_pson(data) end end newtest :search_types, "Find all types" do Puppet::Resource::Type.terminus_class = :rest result = Puppet::Resource::Type.search("*") result.each { |r| p r } end newtest :restful_type, "Find a type and return it via REST" do Puppet::Resource::Type.terminus_class = :rest ARGV.each do |name| p Puppet::Resource::Type.find(name) end end end Suite.new :remote_catalog, "Remote catalog handling" do def prepare $args[:cache] = false # Create a config client and pull the config down @client = Puppet::Network::Client.master.new($args) unless @client.read_cert fail "Could not read client certificate" end if tmp = Puppet::Node::Facts.find($options[:nodes][0]) @facts = tmp.values else raise "Could not find facts for %s" % $optins[:nodes][0] end if host = $options[:fqdn] @facts["fqdn"] = host @facts["hostname"] = host.sub(/\..+/, '') @facts["domain"] = host.sub(/^[^.]+\./, '') end @facts = YAML.dump(@facts) end newtest :getconfig, "Compiled catalog" do @client.driver.getconfig(@facts, "yaml") end # This test will always force a false answer. newtest :fresh, "Checked freshness" do @client.driver.freshness end end Suite.new :file, "File interactions" do def prepare unless $options[:file] fail "You must specify a file (using --file ) to interact with on the server" end @client = Puppet::Network::Client.file.new($args) unless @client.read_cert fail "Could not read client certificate" end end newtest :describe, "Described file" do @client.describe($options[:file], :ignore) end newtest :retrieve, "Retrieved file" do @client.retrieve($options[:file], :ignore) end end Suite.new :filebucket, "Filebucket interactions" do def prepare require 'tempfile' @client = Puppet::FileBucket::Dipper.new($args) end newtest :backup, "Backed up file" do Tempfile.open("bucket_testing") do |f| f.print rand(1024) f.close @client.backup(f.path) end end end # Note that this uses an env variable to determine how many resources per # host to create (with a default of 10). 'repeat' determines how # many hosts to create. You probably will get mad failures if you # use forking and sqlite. # Here's an example run of this test, using sqlite: # RESOURCE_COUNT=50 ext/puppet-test --suite rails --test storage --confdir /tmp/storagetesting --vardir /tmp/storagetesting --repeat 10 Suite.new :rails, "Rails Interactions" do def prepare Puppet::Rails.init @facts = Facter.to_hash if num = ENV["RESOURCECOUNT"] @resources = Integer(num) else @resources = 10 end end Resource = Puppet::Parser::Resource def execute(test, msg) begin send(test) rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "%s failed: %s" % [@name, detail.to_s] end end def mkresource(type, title, parameters) source = "fakesource" res = Resource.new(:type => type, :title => title, :source => source, :scope => "fakescope") parameters.each do |param, value| res.set(param, value, source) end res end def ref(type, title) Resource::Reference.new(:type => type, :title => title) end newtest :storage, "Stored resources" do hostname = "host%s" % @count @facts["hostname"] = hostname args = {:facts => @facts, :name => hostname} # Make all of the resources we want. Make them at least slightly complex, # so we model real resources as close as we can. resources = [] args[:resources] = resources @resources.times do |resnum| exec = mkresource("exec", "exec%s" % resnum, :command => "/bin/echo do something %s" % resnum) exec.tags = %w{exec one} << "exec%s" % resnum user = mkresource("user", "user%s" % resnum, :uid => resnum.to_s, :require => ref("exec", "exec%s" % resnum)) user.tags = %w{user one two} << "user%s" % resnum file = mkresource("file", "/tmp/file%s" % resnum, :owner => resnum.to_s, :require => [ref("exec", "exec%s" % resnum), ref("user", "user%s" % resnum)]) file.tags = %w{file one three} << "file%s" % resnum file.exported = true resources << exec << user << file end Puppet::Rails::Host.store(args) end end Suite.new :report, "Reports interactions" do def prepare Puppet::Transaction::Report.terminus_class = :rest end newtest :empty, "send empty report" do report = Puppet::Transaction::Report.new report.time = Time.now report.save end newtest :fake, "send fake report" do report = Puppet::Transaction::Report.new resourcemetrics = { :total => 12, :out_of_sync => 20, :applied => 45, :skipped => 1, :restarted => 23, :failed_restarts => 1, :scheduled => 10 } report.newmetric(:resources, resourcemetrics) timemetrics = { :resource1 => 10, :resource2 => 50, :resource3 => 40, :resource4 => 20, } report.newmetric(:times, timemetrics) report.newmetric(:changes, :total => 20 ) report.time = Time.now report.save end end $cmdargs = [ [ "--compile", "-c", GetoptLong::NO_ARGUMENT ], [ "--describe", GetoptLong::REQUIRED_ARGUMENT ], [ "--retrieve", "-R", GetoptLong::REQUIRED_ARGUMENT ], [ "--fork", GetoptLong::REQUIRED_ARGUMENT ], [ "--fqdn", "-F", GetoptLong::REQUIRED_ARGUMENT ], [ "--suite", "-s", GetoptLong::REQUIRED_ARGUMENT ], [ "--test", "-t", GetoptLong::REQUIRED_ARGUMENT ], [ "--pause", "-p", GetoptLong::NO_ARGUMENT ], [ "--repeat", "-r", GetoptLong::REQUIRED_ARGUMENT ], [ "--node", "-n", GetoptLong::REQUIRED_ARGUMENT ], [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ], [ "--list", "-l", GetoptLong::NO_ARGUMENT ], [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], [ "--version", "-V", GetoptLong::NO_ARGUMENT ], ] # Add all of the config parameters as valid $options. Puppet.settings.addargs($cmdargs) Puppet::Util::Log.newdestination(:console) Puppet::Node.terminus_class = :plain Puppet::Node.cache_class = :yaml Puppet::Node::Facts.terminus_class = :facter Puppet::Node::Facts.cache_class = :yaml result = GetoptLong.new(*$cmdargs) $args = {} $options = {:repeat => 1, :fork => 0, :pause => false, :nodes => []} begin explicit_waitforcert = false result.each { |opt,arg| case opt # First check to see if the argument is a valid configuration parameter; # if so, set it. when "--compile" $options[:suite] = :configuration $options[:test] = :compile when "--retrieve" $options[:suite] = :file $options[:test] = :retrieve $options[:file] = arg when "--fork" begin $options[:fork] = Integer(arg) rescue => detail $stderr.puts "The argument to 'fork' must be an integer" exit(14) end when "--describe" $options[:suite] = :file $options[:test] = :describe $options[:file] = arg when "--fqdn" $options[:fqdn] = 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 "--suite" $options[:suite] = arg.intern when "--test" $options[:test] = arg.intern when "--file" $options[:file] = arg when "--pause" $options[:pause] = true when "--node" $options[:nodes] << arg when "--list" Suite.suites.sort { |a,b| a.to_s <=> b.to_s }.each do |suite_name| suite = Suite[suite_name] tests = suite.tests.sort { |a,b| a.to_s <=> b.to_s }.join(", ") puts "%20s: %s" % [suite_name, tests] end exit(0) else Puppet.settings.handlearg(opt, arg) end } rescue GetoptLong::InvalidOption => detail $stderr.puts detail $stderr.puts "Try '#{$0} --help'" exit(1) end # Now parse the config Puppet.parse_config $options[:nodes] << Puppet.settings[:certname] if $options[:nodes].empty? $args[:Server] = Puppet[:server] unless $options[:test] $options[:suite] = :remote_catalog $options[:test] = :getconfig end unless $options[:test] raise "A suite was specified without a test" end $pids = [] Suite.run($options[:test]) if $options[:fork] > 0 Process.waitall end diff --git a/ext/yaml_nodes.rb b/ext/yaml_nodes.rb index 2174da09d..3c7077c13 100755 --- a/ext/yaml_nodes.rb +++ b/ext/yaml_nodes.rb @@ -1,99 +1,105 @@ #!/usr/bin/ruby # # = Synopsis # # Use YAML files to provide external node support. # # = Usage # # yaml-nodes # # = Description # # This is a simple example external node script. It allows you to maintain your # node information in yaml files, and it will find a given node's file and produce # it on stdout. It has simple inheritance, in that a node can specify a parent # node, and the node will inherit that parent's classes and parameters. # # = Options # # help:: # Print this help message # # yamldir:: # Specify where the yaml is found. Defaults to 'yaml' in the current directory. # -# = Author +# = License +# Copyright 2011 Luke Kanies # -# Luke Kanies +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# = Copyright +# http://www.apache.org/licenses/LICENSE-2.0 # -# Copyright (c) 2009 Puppet Labs, Inc. -# Licensed under the GPL2 +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. require 'yaml' require 'optparse' BASEDIR = Dir.chdir(File.dirname(__FILE__) + "/..") { Dir.getwd } options = {:yamldir => File.join(BASEDIR, "yaml")} OptionParser.new do |opts| opts.banner = "Usage: yaml-nodes [options] " opts.on("-y dir", "--yamldir dir", "Specify the directory with the YAML files") do |arg| raise "YAML directory #{arg} does not exist or is not a directory" unless FileTest.directory?(arg) options[:yamldir] = arg end opts.on("-h", "--help", "Print this help") do puts opts.help exit(0) end end.parse! # Read in a pure yaml representation of our node. def read_node(node) nodefile = File.join(YAMLDIR, "#{node}.yaml") if FileTest.exist?(nodefile) return YAML.load_file(nodefile) else raise "Could not find information for #{node}" end end node = ARGV[0] info = read_node(node) # Iterate over any provided parents, merging in there information. parents_seen = [] while parent = info["parent"] raise "Found inheritance loop with parent #{parent}" if parents_seen.include?(parent) parents_seen << parent info.delete("parent") parent_info = read_node(parent) # Include any parent classes in our list. if pclasses = parent_info["classes"] info["classes"] += pclasses info["classes"].uniq! end # And inherit parameters from our parent, while preferring our own values. if pparams = parent_info["parameters"] # When using Hash#merge, the hash being merged in wins, and we # want the subnode parameters to be the parent node parameters. info["parameters"] = pparams.merge(info["parameters"]) end # Copy over any parent node name. if pparent = parent_info["parent"] info["parent"] = pparent end end puts YAML.dump(info) diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb index 2ee40227e..fc8616817 100644 --- a/lib/puppet/application/agent.rb +++ b/lib/puppet/application/agent.rb @@ -1,482 +1,481 @@ require 'puppet/application' class Puppet::Application::Agent < Puppet::Application should_parse_config run_mode :agent attr_accessor :args, :agent, :daemon, :host def preinit # Do an initial trap, so that cancels don't get a stack trace. Signal.trap(:INT) do $stderr.puts "Cancelling startup" exit(0) end { :waitforcert => nil, :detailed_exitcodes => false, :verbose => false, :debug => false, :centrallogs => false, :setdest => false, :enable => false, :disable => false, :client => true, :fqdn => nil, :serve => [], :digest => :MD5, :fingerprint => false, }.each do |opt,val| options[opt] = val end @args = {} require 'puppet/daemon' @daemon = Puppet::Daemon.new @daemon.argv = ARGV.dup end option("--centrallogging") option("--disable") option("--enable") option("--debug","-d") option("--fqdn FQDN","-f") option("--test","-t") option("--verbose","-v") option("--fingerprint") option("--digest DIGEST") option("--serve HANDLER", "-s") do |arg| if Puppet::Network::Handler.handler(arg) options[:serve] << arg.to_sym else raise "Could not find handler for #{arg}" end end option("--no-client") do |arg| options[:client] = false end option("--detailed-exitcodes") do |arg| options[:detailed_exitcodes] = true end option("--logdest DEST", "-l DEST") do |arg| begin Puppet::Util::Log.newdestination(arg) options[:setdest] = true rescue => detail puts detail.backtrace if Puppet[:debug] $stderr.puts detail.to_s end end option("--waitforcert WAITFORCERT", "-w") do |arg| options[:waitforcert] = arg.to_i end option("--port PORT","-p") do |arg| @args[:Port] = arg end def help <<-HELP puppet-agent(8) -- The puppet agent daemon ======== SYNOPSIS -------- Retrieves the client configuration from the puppet master and applies it to the local host. This service may be run as a daemon, run periodically using cron (or something similar), or run interactively for testing purposes. USAGE ----- puppet agent [-D|--daemonize|--no-daemonize] [-d|--debug] [--detailed-exitcodes] [--disable] [--enable] [-h|--help] [--certname ] [-l|--logdest syslog||console] [-o|--onetime] [--serve ] [-t|--test] [--noop] [--digest ] [--fingerprint] [-V|--version] [-v|--verbose] [-w|--waitforcert ] DESCRIPTION ----------- 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. Once the client has a signed certificate, it will retrieve its configuration and apply it. USAGE NOTES ----------- '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 background, attempt to get a signed certificate, and retrieve and apply its configuration every 30 minutes. 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). '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. '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). OPTIONS ------- 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 ' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/stable/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet agent with '--genconfig'. * --daemonize: Send the process into the background. This is the default. * --no-daemonize: Do not send the process into the background. * --debug: Enable full debugging. * --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. * --detailed-exitcodes: Provide transaction information via exit codes. If 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. * --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. 'puppet agent' uses the same lock file while it is running, so no more than one 'puppet agent' process is working at a time. 'puppet agent' exits after executing this. * --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). 'puppet agent' exits after executing this. * --certname: Set the certname (unique ID) of the client. The master reads this unique identifying string, which is usually set to the node's fully-qualified domain name, to determine which configurations the node will receive. Use this option to debug setup problems or implement unusual node identification schemes. * --help: Print this help message * --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. * --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 * --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. * --fingerprint: Display the current certificate or certificate signing request fingerprint and then exit. Use the '--digest' option to change the digest algorithm used. * --serve: Start another type of server. By default, 'puppet agent' will start a service handler that allows authenticated and authorized remote nodes to trigger the configuration to be pulled down and applied. You can specify any handler here that does not require configuration, e.g., filebucket, ca, or resource. The handlers are in 'lib/puppet/network/handler', and the names must match exactly, both in the call to 'serve' and in 'namespaceauth.conf'. * --test: Enable the most common options used for testing. These are 'onetime', 'verbose', 'ignorecache', 'no-daemonize', 'no-usecacheonfailure', 'detailed-exit-codes', 'no-splay', and 'show_diff'. * --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. * --verbose: Turn on verbose reporting. * --version: Print the puppet version number and exit. * --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. EXAMPLE ------- $ puppet agent --server puppet.domain.com AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005, 2006 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def run_command return fingerprint if options[:fingerprint] return onetime if Puppet[:onetime] main end def fingerprint unless cert = host.certificate || host.certificate_request $stderr.puts "Fingerprint asked but no certificate nor certificate request have yet been issued" exit(1) return end unless fingerprint = cert.fingerprint(options[:digest]) raise ArgumentError, "Could not get fingerprint for digest '#{options[:digest]}'" end Puppet.notice fingerprint end def onetime unless options[:client] $stderr.puts "onetime is specified but there is no client" exit(43) return end @daemon.set_signal_traps begin report = @agent.run rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err detail.to_s end if not report exit(1) elsif options[:detailed_exitcodes] then exit(report.exit_status) else exit(0) end end def main Puppet.notice "Starting Puppet client version #{Puppet.version}" @daemon.start end # Enable all of the most common test options. def setup_test Puppet.settings.handlearg("--ignorecache") Puppet.settings.handlearg("--no-usecacheonfailure") Puppet.settings.handlearg("--no-splay") Puppet.settings.handlearg("--show_diff") Puppet.settings.handlearg("--no-daemonize") options[:verbose] = true Puppet[:onetime] = true options[:detailed_exitcodes] = true end # Handle the logging settings. def setup_logs if options[:debug] or options[:verbose] Puppet::Util::Log.newdestination(:console) if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end end Puppet::Util::Log.newdestination(:syslog) unless options[:setdest] end def enable_disable_client(agent) if options[:enable] agent.enable elsif options[:disable] agent.disable end exit(0) end def setup_listen unless FileTest.exists?(Puppet[:authconfig]) Puppet.err "Will not start without authorization file #{Puppet[:authconfig]}" exit(14) end handlers = nil if options[:serve].empty? handlers = [:Runner] else handlers = options[:serve] end require 'puppet/network/server' # No REST handlers yet. server = Puppet::Network::Server.new(:xmlrpc_handlers => handlers, :port => Puppet[:puppetport]) @daemon.server = server end def setup_host @host = Puppet::SSL::Host.new waitforcert = options[:waitforcert] || (Puppet[:onetime] ? 0 : 120) cert = @host.wait_for_cert(waitforcert) unless options[:fingerprint] end def setup setup_test if options[:test] setup_logs exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? # If noop is set, then also enable diffs Puppet[:show_diff] = true if Puppet[:noop] args[:Server] = Puppet[:server] if options[:fqdn] args[:FQDN] = options[:fqdn] Puppet[:certname] = options[:fqdn] end if options[:centrallogs] logdest = args[:Server] logdest += ":" + args[:Port] if args.include?(:Port) Puppet::Util::Log.newdestination(logdest) end 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.indirection.terminus_class = :rest # we want the last report to be persisted locally Puppet::Transaction::Report.indirection.cache_class = :yaml # Override the default; puppetd needs this, usually. # You can still override this on the command-line with, e.g., :compiler. Puppet[:catalog_terminus] = :rest # Override the default. Puppet[:facts_terminus] = :facter Puppet::Resource::Catalog.indirection.cache_class = :yaml # We need tomake the client either way, we just don't start it # if --no-client is set. require 'puppet/agent' require 'puppet/configurer' @agent = Puppet::Agent.new(Puppet::Configurer) enable_disable_client(@agent) if options[:enable] or options[:disable] @daemon.agent = agent if options[:client] # It'd be nice to daemonize later, but we have to daemonize before the # waitforcert happens. @daemon.daemonize if Puppet[:daemonize] setup_host @objects = [] # This has to go after the certs are dealt with. if Puppet[:listen] unless Puppet[:onetime] setup_listen else Puppet.notice "Ignoring --listen on onetime run" end end end end diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb index 2b7c9f8fb..bf7b8a988 100644 --- a/lib/puppet/application/apply.rb +++ b/lib/puppet/application/apply.rb @@ -1,257 +1,256 @@ require 'puppet/application' class Puppet::Application::Apply < Puppet::Application should_parse_config option("--debug","-d") option("--execute EXECUTE","-e") do |arg| options[:code] = arg end option("--loadclasses","-L") option("--verbose","-v") option("--use-nodes") option("--detailed-exitcodes") option("--apply catalog", "-a catalog") do |arg| options[:catalog] = arg end option("--logdest LOGDEST", "-l") do |arg| begin Puppet::Util::Log.newdestination(arg) options[:logset] = true rescue => detail $stderr.puts detail.to_s end end def help <<-HELP puppet-apply(8) -- Apply Puppet manifests locally ======== SYNOPSIS -------- Applies a standalone Puppet manifest to the local system. USAGE ----- puppet apply [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose] [-e|--execute] [--detailed-exitcodes] [-l|--logdest ] [--apply ] DESCRIPTION ----------- This is the standalone puppet execution tool; use it to apply individual manifests. When provided with a modulepath, via command line or config file, puppet apply can effectively mimic the catalog that would be served by puppet master with access to the same modules, although there are some subtle differences. When combined with scheduling and an automated system for pushing manifests, this can be used to implement a serverless Puppet site. Most users should use 'puppet agent' and 'puppet master' for site-wide manifests. OPTIONS ------- Note that any configuration parameter that's valid in the configuration file is also a valid long argument. For example, 'modulepath' is a valid configuration parameter, so you can specify '--tags ,' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/stable/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet with '--genconfig'. * --debug: Enable full debugging. * --detailed-exitcodes: Provide transaction information via exit codes. If 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. * --help: Print this help message * --loadclasses: Load any stored classes. 'puppet agent' caches configured classes (usually at /etc/puppet/classes.txt), and setting this option causes all of those classes to be set in your puppet manifest. * --logdest: Where to send messages. Choose between syslog, the console, and a log file. Defaults to sending messages to the console. * --execute: Execute a specific piece of Puppet code * --verbose: Print extra information. * --apply: Apply a JSON catalog (such as one generated with 'puppet master --compile'). You can either specify a JSON file or pipe in JSON from standard input. EXAMPLE ------- $ puppet apply -l /tmp/manifest.log manifest.pp $ puppet apply --modulepath=/root/dev/modules -e "include ntpd::server" AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def run_command if options[:catalog] apply elsif Puppet[:parseonly] parseonly else main end end def apply if options[:catalog] == "-" text = $stdin.read else text = File.read(options[:catalog]) end begin catalog = Puppet::Resource::Catalog.convert_from(Puppet::Resource::Catalog.default_format,text) catalog = Puppet::Resource::Catalog.pson_create(catalog) unless catalog.is_a?(Puppet::Resource::Catalog) rescue => detail raise Puppet::Error, "Could not deserialize catalog from pson: #{detail}" end catalog = catalog.to_ral require 'puppet/configurer' configurer = Puppet::Configurer.new configurer.run :catalog => catalog end def parseonly # Set our code or file to use. if options[:code] or command_line.args.length == 0 Puppet[:code] = options[:code] || STDIN.read else Puppet[:manifest] = command_line.args.shift end begin Puppet::Node::Environment.new(Puppet[:environment]).known_resource_types rescue => detail Puppet.err detail exit 1 end exit 0 end def main # Set our code or file to use. if options[:code] or command_line.args.length == 0 Puppet[:code] = options[:code] || STDIN.read else 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. unless facts = Puppet::Node::Facts.indirection.find(Puppet[:certname]) raise "Could not find facts for #{Puppet[:certname]}" end # Find our Node unless node = Puppet::Node.indirection.find(Puppet[:certname]) raise "Could not find node #{Puppet[:certname]}" end # Merge in the facts. node.merge(facts.values) # Allow users to load the classes that puppet agent creates. if options[:loadclasses] file = Puppet[:classfile] if FileTest.exists?(file) unless FileTest.readable?(file) $stderr.puts "#{file} is not readable" exit(63) end node.classes = File.read(file).split(/[\s\n]+/) end end begin # Compile our catalog starttime = Time.now catalog = Puppet::Resource::Catalog.indirection.find(node.name, :use_node => node) # Translate it to a RAL catalog catalog = catalog.to_ral catalog.finalize catalog.retrieval_duration = Time.now - starttime require 'puppet/configurer' configurer = Puppet::Configurer.new report = configurer.run(:skip_plugin_download => true, :catalog => catalog) exit( options[:detailed_exitcodes] ? report.exit_status : 0 ) rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts detail.message exit(1) end end def setup exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? # If noop is set, then also enable diffs Puppet[:show_diff] = true if Puppet[:noop] Puppet::Util::Log.newdestination(:console) unless options[:logset] client = nil server = nil Signal.trap(:INT) do $stderr.puts "Exiting" exit(1) end # we want the last report to be persisted locally Puppet::Transaction::Report.indirection.cache_class = :yaml if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] Puppet::Util::Log.level = :info end end end diff --git a/lib/puppet/application/cert.rb b/lib/puppet/application/cert.rb index f02fc893c..cbd6fd610 100644 --- a/lib/puppet/application/cert.rb +++ b/lib/puppet/application/cert.rb @@ -1,224 +1,223 @@ require 'puppet/application' class Puppet::Application::Cert < Puppet::Application should_parse_config run_mode :master attr_accessor :all, :ca, :digest, :signed def subcommand @subcommand end def subcommand=(name) # Handle the nasty, legacy mapping of "clean" to "destroy". sub = name.to_sym @subcommand = (sub == :clean ? :destroy : sub) end option("--clean", "-c") do self.subcommand = "destroy" end option("--all", "-a") do @all = true end option("--digest DIGEST") do |arg| @digest = arg end option("--signed", "-s") do @signed = true end option("--debug", "-d") do |arg| Puppet::Util::Log.level = :debug end require 'puppet/ssl/certificate_authority/interface' Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject {|m| m == :destroy }.each do |method| option("--#{method}", "-#{method.to_s[0,1]}") do self.subcommand = method end end option("--verbose", "-v") do Puppet::Util::Log.level = :info end def help puts <<-HELP puppet-cert(8) -- Manage certificates and requests ======== SYNOPSIS -------- Standalone certificate authority. Capable of generating certificates, but mostly used for signing certificate requests from puppet clients. USAGE ----- puppet cert [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose] [-g|--generate] [-l|--list] [-s|--sign] [-r|--revoke] [-p|--print] [-c|--clean] [--verify] [--digest ] [--fingerprint] [host] DESCRIPTION ----------- Because the puppet master service defaults to not signing client certificate requests, this script is available for signing outstanding requests. It can be used to list outstanding requests and then either sign them individually or sign all of them. OPTIONS ------- Note that any configuration parameter that's valid in the configuration file is also a valid long argument. For example, 'ssldir' is a valid configuration parameter, so you can specify '--ssldir ' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/stable/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet cert with '--genconfig'. * --all: Operate on all items. Currently only makes sense with '--sign', '--clean', or '--list'. * --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. * --clean: Remove all files related to a host from puppet cert's storage. This is useful when rebuilding hosts, since new certificate signing requests will only be honored if puppet cert does not have a copy of a signed certificate for that host. The certificate of the host is also revoked. If '--all' is specified then all host certificates, both signed and unsigned, will be removed. * --debug: Enable full debugging. * --generate: Generate a certificate for a named client. A certificate/keypair will be generated for each client named on the command line. * --help: Print this help message * --list: List outstanding certificate requests. If '--all' is specified, signed certificates are also listed, prefixed by '+', and revoked or invalid certificates are prefixed by '-' (the verification outcome is printed in parenthesis). * --print: Print the full-text version of a host's certificate. * --fingerprint: Print the DIGEST (defaults to md5) fingerprint of a host's certificate. * --revoke: Revoke the certificate of a client. The certificate can be specified either by its serial number, given as a decimal number or a hexadecimal number prefixed by '0x', or by its hostname. The certificate is revoked by adding it to the Certificate Revocation List given by the 'cacrl' config parameter. Note that the puppetmasterd needs to be restarted after revoking certificates. * --sign: Sign an outstanding certificate request. Unless '--all' is specified, hosts must be listed after all flags. * --verbose: Enable verbosity. * --version: Print the puppet version number and exit. * --verify: Verify the named certificate against the local CA certificate. EXAMPLE ------- $ puppet cert -l culain.madstop.com $ puppet cert -s culain.madstop.com AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP exit end def main if @all hosts = :all elsif @signed hosts = :signed else hosts = command_line.args.collect { |h| h.downcase } end begin @ca.apply(:revoke, :to => hosts) if subcommand == :destroy @ca.apply(subcommand, :to => hosts, :digest => @digest) rescue => detail puts detail.backtrace if Puppet[:trace] puts detail.to_s exit(24) end end def setup require 'puppet/ssl/certificate_authority' exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? Puppet::Util::Log.newdestination :console if [:generate, :destroy].include? subcommand Puppet::SSL::Host.ca_location = :local else Puppet::SSL::Host.ca_location = :only end begin @ca = Puppet::SSL::CertificateAuthority.new rescue => detail puts detail.backtrace if Puppet[:trace] puts detail.to_s exit(23) end end def parse_options # handle the bareword subcommand pattern. result = super unless self.subcommand then if sub = self.command_line.args.shift then self.subcommand = sub else help end end result end end diff --git a/lib/puppet/application/describe.rb b/lib/puppet/application/describe.rb index 79643159e..8ce20b652 100644 --- a/lib/puppet/application/describe.rb +++ b/lib/puppet/application/describe.rb @@ -1,257 +1,256 @@ require 'puppet/application' class Formatter def initialize(width) @width = width end def wrap(txt, opts) return "" unless txt && !txt.empty? work = (opts[:scrub] ? scrub(txt) : txt) indent = (opts[:indent] ? opts[:indent] : 0) textLen = @width - indent patt = Regexp.new("^(.{0,#{textLen}})[ \n]") prefix = " " * indent res = [] while work.length > textLen if work =~ patt res << $1 work.slice!(0, $MATCH.length) else res << work.slice!(0, textLen) end end res << work if work.length.nonzero? prefix + res.join("\n#{prefix}") end def header(txt, sep = "-") "\n#{txt}\n" + sep * txt.size end private def scrub(text) # For text with no carriage returns, there's nothing to do. return text if text !~ /\n/ indent = nil # If we can match an indentation, then just remove that same level of # indent from every line. if text =~ /^(\s+)/ indent = $1 return text.gsub(/^#{indent}/,'') else return text end end end class TypeDoc def initialize @format = Formatter.new(76) @types = {} Puppet::Type.loadall Puppet::Type.eachtype { |type| next if type.name == :component @types[type.name] = type } end def list_types puts "These are the types known to puppet:\n" @types.keys.sort { |a, b| a.to_s <=> b.to_s }.each do |name| type = @types[name] s = type.doc.gsub(/\s+/, " ") n = s.index(".") if n.nil? s = ".. no documentation .." elsif n > 45 s = s[0, 45] + " ..." else s = s[0, n] end printf "%-15s - %s\n", name, s end end def format_type(name, opts) name = name.to_sym unless @types.has_key?(name) puts "Unknown type #{name}" return end type = @types[name] puts @format.header(name.to_s, "=") puts @format.wrap(type.doc, :indent => 0, :scrub => true) + "\n\n" puts @format.header("Parameters") if opts[:parameters] format_attrs(type, [:property, :param]) else list_attrs(type, [:property, :param]) end if opts[:meta] puts @format.header("Meta Parameters") if opts[:parameters] format_attrs(type, [:meta]) else list_attrs(type, [:meta]) end end if type.providers.size > 0 puts @format.header("Providers") if opts[:providers] format_providers(type) else list_providers(type) end end end # List details about attributes def format_attrs(type, attrs) docs = {} type.allattrs.each do |name| kind = type.attrtype(name) docs[name] = type.attrclass(name).doc if attrs.include?(kind) && name != :provider end docs.sort { |a,b| a[0].to_s <=> b[0].to_s }.each { |name, doc| print "\n- **#{name}**" if type.key_attributes.include?(name) and name != :name puts " (*namevar*)" else puts "" end puts @format.wrap(doc, :indent => 4, :scrub => true) } end # List the names of attributes def list_attrs(type, attrs) params = [] type.allattrs.each do |name| kind = type.attrtype(name) params << name.to_s if attrs.include?(kind) && name != :provider end puts @format.wrap(params.sort.join(", "), :indent => 4) end def format_providers(type) type.providers.sort { |a,b| a.to_s <=> b.to_s }.each { |prov| puts "\n- **#{prov}**" puts @format.wrap(type.provider(prov).doc, :indent => 4, :scrub => true) } end def list_providers(type) list = type.providers.sort { |a,b| a.to_s <=> b.to_s }.join(", ") puts @format.wrap(list, :indent => 4) end end class Puppet::Application::Describe < Puppet::Application banner "puppet describe [options] [type]" should_not_parse_config option("--short", "-s", "Only list parameters without detail") do |arg| options[:parameters] = false end option("--providers","-p") option("--list", "-l") option("--meta","-m") def help <<-HELP puppet-describe(8) -- Display help about resource types ======== SYNOPSIS -------- Prints help about Puppet resource types, providers, and metaparameters. USAGE ----- puppet describe [-h|--help] [-s|--short] [-p|--providers] [-l|--list] [-m|--meta] OPTIONS ------- * --help: Print this help text * --providers: Describe providers in detail for each type * --list: List all types * --meta: List all metaparameters * --short: List only parameters without detail EXAMPLE ------- $ puppet describe --list $ puppet describe file --providers $ puppet describe user -s -m AUTHOR ------ David Lutterkort COPYRIGHT --------- -Copyright (c) 2005 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def preinit options[:parameters] = true end def main doc = TypeDoc.new if options[:list] doc.list_types else options[:types].each { |name| doc.format_type(name, options) } end end def setup options[:types] = command_line.args.dup handle_help(nil) unless options[:list] || options[:types].size > 0 $stderr.puts "Warning: ignoring types when listing all types" if options[:list] && options[:types].size > 0 end end diff --git a/lib/puppet/application/doc.rb b/lib/puppet/application/doc.rb index 74811919e..a88f27c78 100644 --- a/lib/puppet/application/doc.rb +++ b/lib/puppet/application/doc.rb @@ -1,265 +1,264 @@ require 'puppet/application' class Puppet::Application::Doc < Puppet::Application should_not_parse_config run_mode :master attr_accessor :unknown_args, :manifest def preinit {:references => [], :mode => :text, :format => :to_markdown }.each do |name,value| options[name] = value end @unknown_args = [] @manifest = false end option("--all","-a") option("--outputdir OUTPUTDIR","-o") option("--verbose","-v") option("--debug","-d") option("--charset CHARSET") option("--format FORMAT", "-f") do |arg| method = "to_#{arg}" require 'puppet/util/reference' if Puppet::Util::Reference.method_defined?(method) options[:format] = method else raise "Invalid output format #{arg}" end end option("--mode MODE", "-m") do |arg| require 'puppet/util/reference' if Puppet::Util::Reference.modes.include?(arg) or arg.intern==:rdoc options[:mode] = arg.intern else raise "Invalid output mode #{arg}" end end option("--list", "-l") do |arg| require 'puppet/util/reference' puts Puppet::Util::Reference.references.collect { |r| Puppet::Util::Reference.reference(r).doc }.join("\n") exit(0) end option("--reference REFERENCE", "-r") do |arg| options[:references] << arg.intern end def help <<-HELP puppet-doc(8) -- Generate Puppet documentation and references ======== SYNOPSIS -------- Generates a reference for all Puppet types. Largely meant for internal Puppet Labs use. USAGE ----- puppet doc [-a|--all] [-h|--help] [-o|--outputdir ] [-m|--mode text|pdf|rdoc] [-r|--reference ] [--charset ] [] DESCRIPTION ----------- 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. 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. If the command is run with the name of a manifest file as an argument, puppet doc will output a single manifest's documentation on stdout. OPTIONS ------- * --all: Output the docs for all of the reference types. In 'rdoc' modes, this also outputs documentation for all resources * --help: Print this help message * --outputdir: Specifies the directory where to output the rdoc documentation in 'rdoc' mode. * --mode: Determine the output mode. Valid modes are 'text', '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'. * --charset: Used only in 'rdoc' mode. It sets the charset used in the html files produced. EXAMPLE ------- $ puppet doc -r type > /tmp/type_reference.markdown or $ puppet doc --outputdir /tmp/rdoc --mode rdoc /path/to/manifests or $ puppet doc /etc/puppet/manifests/site.pp or $ puppet doc -m pdf -r configuration AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005-2007 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def handle_unknown( opt, arg ) @unknown_args << {:opt => opt, :arg => arg } true end def run_command return[:rdoc].include?(options[:mode]) ? send(options[:mode]) : other end def rdoc exit_code = 0 files = [] unless @manifest env = Puppet::Node::Environment.new files += env.modulepath files << File.dirname(env[:manifest]) end files += command_line.args Puppet.info "scanning: #{files.inspect}" Puppet.settings[:document_all] = options[:all] || false begin require 'puppet/util/rdoc' if @manifest Puppet::Util::RDoc.manifestdoc(files) else options[:outputdir] = "doc" unless options[:outputdir] Puppet::Util::RDoc.rdoc(options[:outputdir], files, options[:charset]) end rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts "Could not generate documentation: #{detail}" exit_code = 1 end exit exit_code end def other text = "" with_contents = options[:references].length <= 1 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) rescue => detail puts detail.backtrace $stderr.puts "Could not generate reference #{name}: #{detail}" exit_code = 1 next end end text += Puppet::Util::Reference.footer unless with_contents # We've only got one reference if options[:mode] == :pdf Puppet::Util::Reference.pdf(text) else puts text end exit exit_code end def setup # sole manifest documentation if command_line.args.size > 0 options[:mode] = :rdoc @manifest = true end if options[:mode] == :rdoc setup_rdoc else setup_reference end end def setup_reference if options[:all] # Don't add dynamic references to the "all" list. require 'puppet/util/reference' options[:references] = Puppet::Util::Reference.references.reject do |ref| Puppet::Util::Reference.reference(ref).dynamic? end end options[:references] << :type if options[:references].empty? end def setup_rdoc(dummy_argument=:work_arround_for_ruby_GC_bug) # consume the unknown options # and feed them as settings if @unknown_args.size > 0 @unknown_args.each do |option| # force absolute path for modulepath when passed on commandline if option[:opt]=="--modulepath" or option[:opt] == "--manifestdir" option[:arg] = option[:arg].split(':').collect { |p| File.expand_path(p) }.join(':') end Puppet.settings.handlearg(option[:opt], option[:arg]) end end # Now parse the config Puppet.parse_config # Handle the logging settings. if options[:debug] or options[:verbose] if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end Puppet::Util::Log.newdestination(:console) end end end diff --git a/lib/puppet/application/filebucket.rb b/lib/puppet/application/filebucket.rb index 063d97db8..6d59ae40b 100644 --- a/lib/puppet/application/filebucket.rb +++ b/lib/puppet/application/filebucket.rb @@ -1,190 +1,189 @@ require 'puppet/application' class Puppet::Application::Filebucket < Puppet::Application should_not_parse_config option("--bucket BUCKET","-b") option("--debug","-d") option("--local","-l") option("--remote","-r") option("--verbose","-v") attr :args def help <<-HELP puppet-filebucket(8) -- Store and retrieve files in a filebucket ======== SYNOPSIS -------- A stand-alone Puppet filebucket client. USAGE ----- puppet filebucket [-h|--help] [-V|--version] [-d|--debug] [-v|--verbose] [-l|--local] [-r|--remote] [-s|--server ] [-b|--bucket ] ... Puppet filebucket can operate in three modes, with only one mode per call: backup: Send one or more files to the specified file bucket. Each sent file is printed with its resulting md5 sum. 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. 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. DESCRIPTION ----------- This is a stand-alone filebucket client for sending files to a local or central filebucket. 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'. OPTIONS ------- Note that any configuration parameter that's valid in the configuration file is also a valid long argument. For example, 'ssldir' is a valid configuration parameter, so you can specify '--ssldir ' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/stable/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet with '--genconfig'. * --debug: Enable full debugging. * --help: Print this help message * --local: Use the local filebucket. This will use the default configuration information. * --remote: Use a remote filebucket. This will use the default configuration information. * --server: The server to send the file to, instead of locally. * --verbose: Print extra information. * --version: Print version information. EXAMPLE ------- $ puppet filebucket backup /etc/passwd /etc/passwd: 429b225650b912a2ee067b0a4cf1e949 $ puppet filebucket restore /tmp/passwd 429b225650b912a2ee067b0a4cf1e949 AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def run_command @args = command_line.args command = args.shift return send(command) if %w{get backup restore}.include? command help end def get md5 = args.shift out = @client.getfile(md5) print out end def backup args.each do |file| unless FileTest.exists?(file) $stderr.puts "#{file}: no such file" next end unless FileTest.readable?(file) $stderr.puts "#{file}: cannot read file" next end md5 = @client.backup(file) puts "#{file}: #{md5}" end end def restore file = args.shift md5 = args.shift @client.restore(file, md5) end def setup Puppet::Log.newdestination(:console) @client = nil @server = nil Signal.trap(:INT) do $stderr.puts "Cancelling" exit(1) end if options[:debug] Puppet::Log.level = :debug elsif options[:verbose] Puppet::Log.level = :info end # Now parse the config Puppet.parse_config exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? require 'puppet/file_bucket/dipper' begin if options[:local] or options[:bucket] path = options[:bucket] || Puppet[:bucketdir] @client = Puppet::FileBucket::Dipper.new(:Path => path) else @client = Puppet::FileBucket::Dipper.new(:Server => Puppet[:server]) end rescue => detail $stderr.puts detail puts detail.backtrace if Puppet[:trace] exit(1) end end end diff --git a/lib/puppet/application/inspect.rb b/lib/puppet/application/inspect.rb index e448cb9e8..30865cfc1 100644 --- a/lib/puppet/application/inspect.rb +++ b/lib/puppet/application/inspect.rb @@ -1,181 +1,179 @@ require 'puppet' require 'puppet/application' require 'puppet/file_bucket/dipper' class Puppet::Application::Inspect < Puppet::Application should_parse_config run_mode :agent option("--debug","-d") option("--verbose","-v") option("--logdest LOGDEST", "-l") do |arg| begin Puppet::Util::Log.newdestination(arg) options[:logset] = true rescue => detail $stderr.puts detail.to_s end end def help <<-HELP puppet-inspect(8) -- Send an inspection report ======== SYNOPSIS -------- Prepares and submits an inspection report to the puppet master. USAGE ----- puppet inspect DESCRIPTION ----------- This command uses the cached catalog from the previous run of 'puppet agent' to determine which attributes of which resources have been marked as auditable with the 'audit' metaparameter. It then examines the current state of the system, writes the state of the specified resource attributes to a report, and submits the report to the puppet master. Puppet inspect does not run as a daemon, and must be run manually or from cron. OPTIONS ------- Any configuration setting which is valid in the configuration file is also a valid long argument, e.g. '--server=master.domain.com'. See the configuration file documentation at http://docs.puppetlabs.com/references/latest/configuration.html for the full list of acceptable settings. AUTHOR ------ Puppet Labs COPYRIGHT --------- - -Copyright (c) 2011 Puppet Labs, LLC -Licensed under the GNU General Public License version 2 +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def setup exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? raise "Inspect requires reporting to be enabled. Set report=true in puppet.conf to enable reporting." unless Puppet[:report] @report = Puppet::Transaction::Report.new("inspect") Puppet::Util::Log.newdestination(@report) Puppet::Util::Log.newdestination(:console) unless options[:logset] Signal.trap(:INT) do $stderr.puts "Exiting" exit(1) end if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] Puppet::Util::Log.level = :info end Puppet::Transaction::Report.indirection.terminus_class = :rest Puppet::Resource::Catalog.indirection.terminus_class = :yaml end def run_command benchmark(:notice, "Finished inspection") do retrieval_starttime = Time.now unless catalog = Puppet::Resource::Catalog.indirection.find(Puppet[:certname]) raise "Could not find catalog for #{Puppet[:certname]}" end @report.configuration_version = catalog.version inspect_starttime = Time.now @report.add_times("config_retrieval", inspect_starttime - retrieval_starttime) if Puppet[:archive_files] dipper = Puppet::FileBucket::Dipper.new(:Server => Puppet[:archive_file_server]) end catalog.to_ral.resources.each do |ral_resource| audited_attributes = ral_resource[:audit] next unless audited_attributes status = Puppet::Resource::Status.new(ral_resource) begin audited_resource = ral_resource.to_resource rescue StandardError => detail puts detail.backtrace if Puppet[:trace] ral_resource.err "Could not inspect #{ral_resource}; skipping: #{detail}" audited_attributes.each do |name| event = ral_resource.event( :property => name, :status => "failure", :audited => true, :message => "failed to inspect #{name}" ) status.add_event(event) end else audited_attributes.each do |name| next if audited_resource[name].nil? # Skip :absent properties of :absent resources. Really, it would be nicer if the RAL returned nil for those, but it doesn't. ~JW if name == :ensure or audited_resource[:ensure] != :absent or audited_resource[name] != :absent event = ral_resource.event( :previous_value => audited_resource[name], :property => name, :status => "audit", :audited => true, :message => "inspected value is #{audited_resource[name].inspect}" ) status.add_event(event) end end end if Puppet[:archive_files] and ral_resource.type == :file and audited_attributes.include?(:content) path = ral_resource[:path] if File.readable?(path) begin dipper.backup(path) rescue StandardError => detail Puppet.warning detail end end end @report.add_resource_status(status) end finishtime = Time.now @report.add_times("inspect", finishtime - inspect_starttime) @report.finalize_report begin Puppet::Transaction::Report.indirection.save(@report) rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not send report: #{detail}" end end end end diff --git a/lib/puppet/application/kick.rb b/lib/puppet/application/kick.rb index da93c0182..536699442 100644 --- a/lib/puppet/application/kick.rb +++ b/lib/puppet/application/kick.rb @@ -1,353 +1,352 @@ require 'puppet/application' class Puppet::Application::Kick < Puppet::Application should_not_parse_config attr_accessor :hosts, :tags, :classes option("--all","-a") option("--foreground","-f") option("--debug","-d") option("--ping","-P") option("--test") option("--host HOST") do |arg| @hosts << arg end option("--tag TAG", "-t") do |arg| @tags << arg end option("--class CLASS", "-c") do |arg| @classes << arg end option("--no-fqdn", "-n") do |arg| options[:fqdn] = false end option("--parallel PARALLEL", "-p") do |arg| begin options[:parallel] = Integer(arg) rescue $stderr.puts "Could not convert #{arg.inspect} to an integer" exit(23) end end def help <<-HELP puppet-kick(8) -- Remotely control puppet agent ======== SYNOPSIS -------- Trigger a puppet agent run on a set of hosts. USAGE ----- puppet kick [-a|--all] [-c|--class ] [-d|--debug] [-f|--foreground] [-h|--help] [--host ] [--no-fqdn] [--ignoreschedules] [-t|--tag ] [--test] [-p|--ping] [ [...]] DESCRIPTION ----------- This script can be used to connect to a set of machines running 'puppet agent' and trigger them to run their configurations. The most common usage would be to specify a class of hosts and a set of tags, and 'puppet kick' would look up in LDAP all of the hosts matching that class, then connect to each host and trigger a run of all of the objects with the specified tags. If you are not storing your host configurations in LDAP, you can specify hosts manually. You will most likely have to run 'puppet kick' as root to get access to the SSL certificates. 'puppet kick' reads 'puppet master''s configuration file, so that it can copy things like LDAP settings. USAGE NOTES ----------- 'puppet kick' is useless unless 'puppet agent' is listening. 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. An example file looks like this: [fileserver] allow *.madstop.com [puppetmaster] allow *.madstop.com [puppetrunner] allow culain.madstop.com This is what you would install on your Puppet master; non-master hosts could leave off the 'fileserver' and 'puppetmaster' namespaces. OPTIONS ------- Note that any configuration parameter that's valid in the configuration file is also a valid long argument. For example, 'ssldir' is a valid configuration parameter, so you can specify '--ssldir ' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/latest/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet master with '--genconfig'. * --all: Connect to all available hosts. Requires LDAP support at this point. * --class: Specify a class of machines to which to connect. This only works if you have LDAP configured, at the moment. * --debug: Enable full debugging. * --foreground: Run each configuration in the foreground; that is, when connecting to a host, do not return until the host has finished its run. The default is false. * --help: Print this help message * --host: A specific host to which to connect. This flag can be specified more than once. * --ignoreschedules: Whether the client should ignore schedules when running its configuration. This can be used to force the client to perform work it would not normally perform so soon. The default is false. * --parallel: How parallel to make the connections. Parallelization is provided by forking for each client to which to connect. The default is 1, meaning serial execution. * --tag: Specify a tag for selecting the objects to apply. Does not work with the --test option. * --test: Print the hosts you would connect to but do not actually connect. This option requires LDAP support at this point. * --ping: Do a ICMP echo against the target host. Skip hosts that don't respond to ping. EXAMPLE ------- $ sudo puppet kick -p 10 -t remotefile -t webserver host1 host2 AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def run_command @hosts += command_line.args options[:test] ? test : main end def test puts "Skipping execution in test mode" exit(0) end def main require 'puppet/network/client' Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap? require 'puppet/util/ldap/connection' todo = @hosts.dup failures = [] # Now do the actual work go = true while go # If we don't have enough children in process and we still have hosts left to # do, then do the next host. if @children.length < options[:parallel] and ! todo.empty? host = todo.shift pid = fork do run_for_host(host) end @children[pid] = host else # Else, see if we can reap a process. begin pid = Process.wait if host = @children[pid] # Remove our host from the list of children, so the parallelization # continues working. @children.delete(pid) failures << host if $CHILD_STATUS.exitstatus != 0 print "#{host} finished with exit code #{$CHILD_STATUS.exitstatus}\n" else $stderr.puts "Could not find host for PID #{pid} with status #{$CHILD_STATUS.exitstatus}" end rescue Errno::ECHILD # There are no children left, so just exit unless there are still # children left to do. next unless todo.empty? if failures.empty? puts "Finished" exit(0) else puts "Failed: #{failures.join(", ")}" exit(3) end end end end end def run_for_host(host) if options[:ping] out = %x{ping -c 1 #{host}} unless $CHILD_STATUS == 0 $stderr.print "Could not contact #{host}\n" exit($CHILD_STATUS) end end require 'puppet/run' Puppet::Run.indirection.terminus_class = :rest port = Puppet[:puppetport] url = ["https://#{host}:#{port}", "production", "run", host].join('/') print "Triggering #{host}\n" begin run_options = { :tags => @tags, :background => ! options[:foreground], :ignoreschedules => options[:ignoreschedules] } run = Puppet::Run.indirection.save(Puppet::Run.new( run_options ), url) puts "Getting status" result = run.status puts "status is #{result}" rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts "Host #{host} failed: #{detail}\n" exit(2) end case result when "success"; exit(0) when "running" $stderr.puts "Host #{host} is already running" exit(3) else $stderr.puts "Host #{host} returned unknown answer '#{result}'" exit(12) end end def initialize(*args) super @hosts = [] @classes = [] @tags = [] end def preinit [:INT, :TERM].each do |signal| Signal.trap(signal) do $stderr.puts "Cancelling" exit(1) end end options[:parallel] = 1 options[:verbose] = true options[:fqdn] = true options[:ignoreschedules] = false options[:foreground] = false end def setup if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end # Now parse the config Puppet.parse_config if Puppet[:node_terminus] == "ldap" and (options[:all] or @classes) if options[:all] @hosts = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name } puts "all: #{@hosts.join(", ")}" else @hosts = [] @classes.each do |klass| list = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name } puts "#{klass}: #{list.join(", ")}" @hosts += list end end elsif ! @classes.empty? $stderr.puts "You must be using LDAP to specify host classes" exit(24) end @children = {} # If we get a signal, then kill all of our children and get out. [:INT, :TERM].each do |signal| Signal.trap(signal) do Puppet.notice "Caught #{signal}; shutting down" @children.each do |pid, host| Process.kill("INT", pid) end waitall exit(1) end end end end diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb index 78499a92a..f93894d99 100644 --- a/lib/puppet/application/master.rb +++ b/lib/puppet/application/master.rb @@ -1,239 +1,238 @@ require 'puppet/application' class Puppet::Application::Master < Puppet::Application should_parse_config run_mode :master option("--debug", "-d") option("--verbose", "-v") # internal option, only to be used by ext/rack/config.ru option("--rack") option("--compile host", "-c host") do |arg| options[:node] = arg end option("--logdest DEST", "-l DEST") do |arg| begin Puppet::Util::Log.newdestination(arg) options[:setdest] = true rescue => detail puts detail.backtrace if Puppet[:debug] $stderr.puts detail.to_s end end def help <<-HELP puppet-master(8) -- The puppet master daemon ======== SYNOPSIS -------- The central puppet server. Functions as a certificate authority by default. USAGE ----- puppet master [-D|--daemonize|--no-daemonize] [-d|--debug] [-h|--help] [-l|--logdest |console|syslog] [-v|--verbose] [-V|--version] [--compile ] DESCRIPTION ----------- This command starts an instance of puppet master, running as a daemon and using Ruby's built-in Webrick webserver. Puppet master can also be managed by other application servers; when this is the case, this executable is not used. OPTIONS ------- Note that any configuration parameter that's valid in the configuration file is also a valid long argument. For example, 'ssldir' is a valid configuration parameter, so you can specify '--ssldir ' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/stable/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet master with '--genconfig'. * --daemonize: Send the process into the background. This is the default. * --no-daemonize: Do not send the process into the background. * --debug: Enable full debugging. * --help: Print this help message. * --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. * --verbose: Enable verbosity. * --version: Print the puppet version number and exit. * --compile: Compile a catalogue and output it in JSON from the puppet master. Uses facts contained in the $vardir/yaml/ directory to compile the catalog. EXAMPLE ------- puppet master AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def preinit Signal.trap(:INT) do $stderr.puts "Cancelling startup" exit(0) end # Create this first-off, so we have ARGV require 'puppet/daemon' @daemon = Puppet::Daemon.new @daemon.argv = ARGV.dup end def run_command if options[:node] compile elsif Puppet[:parseonly] parseonly else main end end def compile Puppet::Util::Log.newdestination :console raise ArgumentError, "Cannot render compiled catalogs without pson support" unless Puppet.features.pson? begin unless catalog = Puppet::Resource::Catalog.indirection.find(options[:node]) raise "Could not compile catalog for #{options[:node]}" end jj catalog.to_resource rescue => detail $stderr.puts detail exit(30) end exit(0) end def parseonly begin Puppet::Node::Environment.new(Puppet[:environment]).known_resource_types rescue => detail Puppet.err detail exit 1 end exit(0) end def main require 'etc' require 'puppet/file_serving/content' require 'puppet/file_serving/metadata' xmlrpc_handlers = [:Status, :FileServer, :Master, :Report, :Filebucket] xmlrpc_handlers << :CA if Puppet[:ca] # Make sure we've got a localhost ssl cert Puppet::SSL::Host.localhost # And now configure our server to *only* hit the CA for data, because that's # all it will have write access to. Puppet::SSL::Host.ca_location = :only if Puppet::SSL::CertificateAuthority.ca? if Puppet.features.root? begin Puppet::Util.chuser rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts "Could not change user to #{Puppet[:user]}: #{detail}" exit(39) end end unless options[:rack] require 'puppet/network/server' @daemon.server = Puppet::Network::Server.new(:xmlrpc_handlers => xmlrpc_handlers) @daemon.daemonize if Puppet[:daemonize] else require 'puppet/network/http/rack' @app = Puppet::Network::HTTP::Rack.new(:xmlrpc_handlers => xmlrpc_handlers, :protocols => [:rest, :xmlrpc]) end Puppet.notice "Starting Puppet master version #{Puppet.version}" unless options[:rack] @daemon.start else return @app end end def setup # Handle the logging settings. if options[:debug] or options[:verbose] if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end unless Puppet[:daemonize] or options[:rack] Puppet::Util::Log.newdestination(:console) options[:setdest] = true end end Puppet::Util::Log.newdestination(:syslog) unless options[:setdest] exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? Puppet.settings.use :main, :master, :ssl, :metrics # Cache our nodes in yaml. Currently not configurable. Puppet::Node.indirection.cache_class = :yaml # Configure all of the SSL stuff. if Puppet::SSL::CertificateAuthority.ca? Puppet::SSL::Host.ca_location = :local Puppet.settings.use :ca Puppet::SSL::CertificateAuthority.instance else Puppet::SSL::Host.ca_location = :none end end end diff --git a/lib/puppet/application/queue.rb b/lib/puppet/application/queue.rb index de8aea32a..e56fde281 100644 --- a/lib/puppet/application/queue.rb +++ b/lib/puppet/application/queue.rb @@ -1,165 +1,164 @@ require 'puppet/application' require 'puppet/util' class Puppet::Application::Queue < Puppet::Application should_parse_config attr_accessor :daemon def preinit require 'puppet/daemon' @daemon = Puppet::Daemon.new @daemon.argv = ARGV.dup Puppet::Util::Log.newdestination(:console) # Do an initial trap, so that cancels don't get a stack trace. # This exits with exit code 1 Signal.trap(:INT) do $stderr.puts "Caught SIGINT; shutting down" exit(1) end # This is a normal shutdown, so code 0 Signal.trap(:TERM) do $stderr.puts "Caught SIGTERM; shutting down" exit(0) end { :verbose => false, :debug => false }.each do |opt,val| options[opt] = val end end option("--debug","-d") option("--verbose","-v") def help <<-HELP puppet-queue(8) -- Queuing daemon for asynchronous storeconfigs ======== SYNOPSIS -------- Retrieves serialized storeconfigs records from a queue and processes them in order. USAGE ----- puppet queue [-d|--debug] [-v|--verbose] DESCRIPTION ----------- This application runs as a daemon and processes storeconfigs data, retrieving the data from a stomp server message queue and writing it to a database. For more information, including instructions for properly setting up your puppet master and message queue, see the documentation on setting up asynchronous storeconfigs at: http://projects.puppetlabs.com/projects/1/wiki/Using_Stored_Configuration OPTIONS ------- 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 ' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/stable/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet queue with '--genconfig'. * --debug: Enable full debugging. * --help: Print this help message * --verbose: Turn on verbose reporting. * --version: Print the puppet version number and exit. EXAMPLE ------- $ puppet queue AUTHOR ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2009 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end 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, passing it to save should suffice # to put it through to the database via its active_record indirector (which is determined # by the terminus_class = :active_record setting above) Puppet::Util.benchmark(:notice, "Processing queued catalog for #{catalog.name}") do begin Puppet::Resource::Catalog.indirection.save(catalog) rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not save queued catalog for #{catalog.name}: #{detail}" end end end Thread.list.each { |thread| thread.join } end # Handle the logging settings. def setup_logs if options[:debug] or options[:verbose] Puppet::Util::Log.newdestination(:console) if options[:debug] Puppet::Util::Log.level = :debug else Puppet::Util::Log.level = :info end end end def setup unless Puppet.features.stomp? raise ArgumentError, "Could not load the 'stomp' library, which must be present for queueing to work. You must install the required library." end setup_logs exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? require 'puppet/resource/catalog' Puppet::Resource::Catalog.indirection.terminus_class = :active_record daemon.daemonize if Puppet[:daemonize] # We want to make sure that we don't have a cache # class set up, because if storeconfigs is enabled, # we'll get a loop of continually caching the catalog # for storage again. Puppet::Resource::Catalog.indirection.cache_class = nil end end diff --git a/lib/puppet/application/resource.rb b/lib/puppet/application/resource.rb index 3995c285b..6ef87d68f 100644 --- a/lib/puppet/application/resource.rb +++ b/lib/puppet/application/resource.rb @@ -1,221 +1,220 @@ require 'puppet/application' class Puppet::Application::Resource < Puppet::Application should_not_parse_config attr_accessor :host, :extra_params def preinit @extra_params = [] @host = nil Facter.loadfacts end option("--debug","-d") option("--verbose","-v") option("--edit","-e") option("--host HOST","-H") do |arg| @host = arg end option("--types", "-t") do |arg| types = [] Puppet::Type.loadall Puppet::Type.eachtype do |t| next if t.name == :component types << t.name.to_s end puts types.sort exit end option("--param PARAM", "-p") do |arg| @extra_params << arg.to_sym end def help <<-HELP puppet-resource(8) -- The resource abstraction layer shell ======== SYNOPSIS -------- Uses the Puppet RAL to directly interact with the system. USAGE ----- puppet resource [-h|--help] [-d|--debug] [-v|--verbose] [-e|--edit] [-H|--host ] [-p|--param ] [-t|--types] [] [= ...] DESCRIPTION ----------- This command provides simple facilities for converting current system state into Puppet code, along with some ability to modify the current state using Puppet's RAL. By default, you must at least provide a type to list, in which case puppet resource will tell you everything it knows about all resources of that type. You can optionally specify an instance name, and puppet resource will only describe that single instance. If given a type, a name, and a series of = pairs, puppet resource will modify the state of the specified resource. Alternately, if given a type, a name, and the '--edit' flag, puppet resource will write its output to a file, open that file in an editor, and then apply the saved file as a Puppet transaction. OPTIONS ------- Note that any configuration parameter that's valid in the configuration file is also a valid long argument. For example, 'ssldir' is a valid configuration parameter, so you can specify '--ssldir ' as an argument. See the configuration file documentation at http://docs.puppetlabs.com/references/stable/configuration.html for the full list of acceptable parameters. A commented list of all configuration options can also be generated by running puppet with '--genconfig'. * --debug: Enable full debugging. * --edit: 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. * --host: When specified, connect to the resource server on the named host and retrieve the list of resouces of the type specified. * --help: Print this help message. * --param: Add more parameters to be outputted from queries. * --types: List all available types. * --verbose: Print extra information. EXAMPLE ------- This example uses `puppet resource` to return a 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 ------ Luke Kanies COPYRIGHT --------- -Copyright (c) 2005-2007 Puppet Labs, LLC Licensed under the GNU Public -License +Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end def main args = command_line.args type = args.shift or raise "You must specify the type to display" typeobj = Puppet::Type.type(type) or raise "Could not find type #{type}" name = args.shift params = {} args.each do |setting| if setting =~ /^(\w+)=(.+)$/ params[$1] = $2 else raise "Invalid parameter setting #{setting}" end end raise "You cannot edit a remote host" if options[:edit] and @host properties = typeobj.properties.collect { |s| s.name } format = proc {|trans| trans.dup.collect do |param, value| if value.nil? or value.to_s.empty? trans.delete(param) elsif value.to_s == "absent" and param.to_s != "ensure" trans.delete(param) end trans.delete(param) unless properties.include?(param) or @extra_params.include?(param) end trans.to_manifest } if @host Puppet::Resource.indirection.terminus_class = :rest port = Puppet[:puppetport] key = ["https://#{host}:#{port}", "production", "resources", type, name].join('/') else key = [type, name].join('/') end text = if name if params.empty? [ Puppet::Resource.indirection.find( key ) ] else [ Puppet::Resource.indirection.save(Puppet::Resource.new( type, name, :parameters => params ), key) ] end else Puppet::Resource.indirection.search( key, {} ) end.map(&format).join("\n") if options[:edit] file = "/tmp/x2puppet-#{Process.pid}.pp" begin File.open(file, "w") do |f| f.puts text end ENV["EDITOR"] ||= "vi" system(ENV["EDITOR"], file) system("puppet -v #{file}") ensure #if FileTest.exists? file # File.unlink(file) #end end else puts text end end def setup Puppet::Util::Log.newdestination(:console) # Now parse the config Puppet.parse_config if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] Puppet::Util::Log.level = :info end end end diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb index 9bd949a08..ce0401ad2 100644 --- a/lib/puppet/network/http_server/mongrel.rb +++ b/lib/puppet/network/http_server/mongrel.rb @@ -1,150 +1,130 @@ #!/usr/bin/env ruby # File: 06-11-14-mongrel_xmlrpc.rb # Author: Manuel Holtgrewe # # Copyright (c) 2006 Manuel Holtgrewe, 2007 Luke Kanies # -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS -# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - # This file is based heavily on a file retrieved from # http://ttt.ggnore.net/2006/11/15/xmlrpc-with-mongrel-and-ruby-off-rails/ require 'rubygems' require 'mongrel' require 'xmlrpc/server' require 'puppet/network/xmlrpc/server' require 'puppet/network/http_server' require 'puppet/network/client_request' require 'puppet/network/handler' require 'resolv' # This handler can be hooked into Mongrel to accept HTTP requests. After # checking whether the request itself is sane, the handler forwards it # to an internal instance of XMLRPC::BasicServer to process it. # # You can access the server by calling the Handler's "xmlrpc_server" # attribute accessor method and add XMLRPC handlers there. For example: # #
 # handler = XmlRpcHandler.new
 # handler.xmlrpc_server.add_handler("my.add") { |a, b| a.to_i + b.to_i }
 # 
module Puppet::Network class HTTPServer::Mongrel < ::Mongrel::HttpHandler attr_reader :xmlrpc_server def initialize(handlers) if Puppet[:debug] $mongrel_debug_client = true Puppet.debug 'Mongrel client debugging enabled. [$mongrel_debug_client = true].' end # Create a new instance of BasicServer. We are supposed to subclass it # but that does not make sense since we would not introduce any new # behaviour and we have to subclass Mongrel::HttpHandler so our handler # works for Mongrel. @xmlrpc_server = Puppet::Network::XMLRPCServer.new handlers.each do |name| unless handler = Puppet::Network::Handler.handler(name) raise ArgumentError, "Invalid handler #{name}" end @xmlrpc_server.add_handler(handler.interface, handler.new({})) end end # This method produces the same results as XMLRPC::CGIServer.serve # from Ruby's stdlib XMLRPC implementation. def process(request, response) # Make sure this has been a POST as required for XMLRPC. request_method = request.params[Mongrel::Const::REQUEST_METHOD] || Mongrel::Const::GET if request_method != "POST" response.start(405) { |head, out| out.write("Method Not Allowed") } return end # Make sure the user has sent text/xml data. request_mime = request.params["CONTENT_TYPE"] || "text/plain" if parse_content_type(request_mime).first != "text/xml" response.start(400) { |head, out| out.write("Bad Request") } return end # Make sure there is data in the body at all. length = request.params[Mongrel::Const::CONTENT_LENGTH].to_i if length <= 0 response.start(411) { |head, out| out.write("Length Required") } return end # Check the body to be valid. if request.body.nil? or request.body.size != length response.start(400) { |head, out| out.write("Bad Request") } return end info = client_info(request) # All checks above passed through response.start(200) do |head, out| head["Content-Type"] = "text/xml; charset=utf-8" begin out.write(@xmlrpc_server.process(request.body, info)) rescue => detail puts detail.backtrace raise end end end private def client_info(request) params = request.params ip = params["HTTP_X_FORWARDED_FOR"] ? params["HTTP_X_FORWARDED_FOR"].split(',').last.strip : params["REMOTE_ADDR"] # JJM #906 The following dn.match regular expression is forgiving # enough to match the two Distinguished Name string contents # coming from Apache, Pound or other reverse SSL proxies. if dn = params[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/) client = dn_matchdata[1].to_str valid = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS') else begin client = Resolv.getname(ip) rescue => detail Puppet.err "Could not resolve #{ip}: #{detail}" client = "unknown" end valid = false end info = Puppet::Network::ClientRequest.new(client, ip, valid) info end # Taken from XMLRPC::ParseContentType def parse_content_type(str) a, *b = str.split(";") return a.strip, *b end end end diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb index 5488c6674..a16f54bd7 100644 --- a/lib/puppet/provider/augeas/augeas.rb +++ b/lib/puppet/provider/augeas/augeas.rb @@ -1,387 +1,383 @@ -#-- -# Copyright (C) 2008 Red Hat Inc. # -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. +# Copyright 2011 Bryan Kearney # -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# http://www.apache.org/licenses/LICENSE-2.0 # -# Author: Bryan Kearney +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. require 'augeas' if Puppet.features.augeas? require 'strscan' Puppet::Type.type(:augeas).provide(:augeas) do include Puppet::Util confine :true => Puppet.features.augeas? has_features :parse_commands, :need_to_run?,:execute_changes SAVE_NOOP = "noop" SAVE_OVERWRITE = "overwrite" COMMANDS = { "set" => [ :path, :string ], "setm" => [ :path, :string, :string ], "rm" => [ :path ], "clear" => [ :path ], "mv" => [ :path, :path ], "insert" => [ :string, :string, :path ], "get" => [ :path, :comparator, :string ], "defvar" => [ :string, :path ], "defnode" => [ :string, :path, :string ], "match" => [ :path, :glob ], "size" => [:comparator, :int], "include" => [:string], "not_include" => [:string], "==" => [:glob], "!=" => [:glob] } COMMANDS["ins"] = COMMANDS["insert"] COMMANDS["remove"] = COMMANDS["rm"] COMMANDS["move"] = COMMANDS["mv"] attr_accessor :aug # Extracts an 2 dimensional array of commands which are in the # form of command path value. # The input can be # - A string with one command # - A string with many commands per line # - An array of strings. def parse_commands(data) context = resource[:context] # Add a trailing / if it is not there if (context.length > 0) context << "/" if context[-1, 1] != "/" end data = data.split($/) if data.is_a?(String) data = data.flatten args = [] data.each do |line| line.strip! next if line.nil? || line.empty? argline = [] sc = StringScanner.new(line) cmd = sc.scan(/\w+|==|!=/) formals = COMMANDS[cmd] fail("Unknown command #{cmd}") unless formals argline << cmd narg = 0 formals.each do |f| sc.skip(/\s+/) narg += 1 if f == :path start = sc.pos nbracket = 0 inSingleTick = false inDoubleTick = false begin sc.skip(/([^\]\[\s\\'"]|\\.)+/) ch = sc.getch nbracket += 1 if ch == "[" nbracket -= 1 if ch == "]" inSingleTick = !inSingleTick if ch == "'" inDoubleTick = !inDoubleTick if ch == "\"" fail("unmatched [") if nbracket < 0 end until ((nbracket == 0 && !inSingleTick && !inDoubleTick && (ch =~ /\s/)) || sc.eos?) len = sc.pos - start len -= 1 unless sc.eos? unless p = sc.string[start, len] fail("missing path argument #{narg} for #{cmd}") end # Rip off any ticks if they are there. p = p[1, (p.size - 2)] if p[0,1] == "'" || p[0,1] == "\"" p.chomp!("/") if p[0,1] != '$' && p[0,1] != "/" argline << context + p else argline << p end elsif f == :string delim = sc.peek(1) if delim == "'" || delim == "\"" sc.getch argline << sc.scan(/([^\\#{delim}]|(\\.))*/) sc.getch else argline << sc.scan(/[^\s]+/) end fail("missing string argument #{narg} for #{cmd}") unless argline[-1] elsif f == :comparator argline << sc.scan(/(==|!=|=~|<|<=|>|>=)/) unless argline[-1] puts sc.rest fail("invalid comparator for command #{cmd}") end elsif f == :int argline << sc.scan(/\d+/).to_i elsif f== :glob argline << sc.rest end end args << argline end args end def open_augeas unless @aug flags = Augeas::NONE flags = Augeas::TYPE_CHECK if resource[:type_check] == :true flags |= Augeas::NO_MODL_AUTOLOAD if resource[:incl] root = resource[:root] load_path = resource[:load_path] debug("Opening augeas with root #{root}, lens path #{load_path}, flags #{flags}") @aug = Augeas::open(root, load_path,flags) debug("Augeas version #{get_augeas_version} is installed") if get_augeas_version >= "0.3.6" if resource[:incl] aug.set("/augeas/load/Xfm/lens", resource[:lens]) aug.set("/augeas/load/Xfm/incl", resource[:incl]) aug.load end end @aug end def close_augeas if @aug @aug.close debug("Closed the augeas connection") @aug = nil end end # Used by the need_to_run? method to process get filters. Returns # true if there is a match, false if otherwise # Assumes a syntax of get /files/path [COMPARATOR] value def process_get(cmd_array) return_value = false #validate and tear apart the command fail ("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 4 cmd = cmd_array.shift path = cmd_array.shift comparator = cmd_array.shift arg = cmd_array.join(" ") #check the value in augeas result = @aug.get(path) || '' case comparator when "!=" return_value = (result != arg) when "=~" regex = Regexp.new(arg) return_value = (result =~ regex) else return_value = (result.send(comparator, arg)) end !!return_value end # Used by the need_to_run? method to process match filters. Returns # true if there is a match, false if otherwise def process_match(cmd_array) return_value = false #validate and tear apart the command fail("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 3 cmd = cmd_array.shift path = cmd_array.shift # Need to break apart the clause clause_array = parse_commands(cmd_array.shift)[0] verb = clause_array.shift #Get the values from augeas result = @aug.match(path) || [] fail("Error trying to match path '#{path}'") if (result == -1) # Now do the work case verb when "size" fail("Invalid command: #{cmd_array.join(" ")}") if clause_array.length != 2 comparator = clause_array.shift arg = clause_array.shift case comparator when "!=" return_value = !(result.size.send(:==, arg)) else return_value = (result.size.send(comparator, arg)) end when "include" arg = clause_array.shift return_value = result.include?(arg) when "not_include" arg = clause_array.shift return_value = !result.include?(arg) when "==" begin arg = clause_array.shift new_array = eval arg return_value = (result == new_array) rescue fail("Invalid array in command: #{cmd_array.join(" ")}") end when "!=" begin arg = clause_array.shift new_array = eval arg return_value = (result != new_array) rescue fail("Invalid array in command: #{cmd_array.join(" ")}") end end !!return_value end def get_augeas_version @aug.get("/augeas/version") || "" end def set_augeas_save_mode(mode) @aug.set("/augeas/save", mode) end def files_changed? saved_files = @aug.match("/augeas/events/saved") saved_files.size > 0 end # Determines if augeas acutally needs to run. def need_to_run? force = resource[:force] return_value = true begin open_augeas filter = resource[:onlyif] unless filter == "" cmd_array = parse_commands(filter)[0] command = cmd_array[0]; begin case command when "get"; return_value = process_get(cmd_array) when "match"; return_value = process_match(cmd_array) end rescue SystemExit,NoMemoryError raise rescue Exception => e fail("Error sending command '#{command}' with params #{cmd_array[1..-1].inspect}/#{e.message}") end end unless force # If we have a verison of augeas which is at least 0.3.6 then we # can make the changes now, see if changes were made, and # actually do the save. if return_value and get_augeas_version >= "0.3.6" debug("Will attempt to save and only run if files changed") set_augeas_save_mode(SAVE_NOOP) do_execute_changes save_result = @aug.save saved_files = @aug.match("/augeas/events/saved") if save_result and not files_changed? debug("Skipping because no files were changed") return_value = false else debug("Files changed, should execute") end end end ensure close_augeas end return_value end def execute_changes # Re-connect to augeas, and re-execute the changes begin open_augeas set_augeas_save_mode(SAVE_OVERWRITE) if get_augeas_version >= "0.3.6" do_execute_changes success = @aug.save fail("Save failed with return code #{success}") if success != true ensure close_augeas end :executed end # Actually execute the augeas changes. def do_execute_changes commands = parse_commands(resource[:changes]) commands.each do |cmd_array| fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2 command = cmd_array[0] cmd_array.shift begin case command when "set" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.set(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "setm" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.setm(cmd_array[0], cmd_array[1], cmd_array[2]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) when "rm", "remove" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.rm(cmd_array[0]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) when "clear" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.clear(cmd_array[0]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "insert", "ins" label = cmd_array[0] where = cmd_array[1] path = cmd_array[2] case where when "before"; before = true when "after"; before = false else fail("Invalid value '#{where}' for where param") end debug("sending command '#{command}' with params #{[label, where, path].inspect}") rv = aug.insert(path, label, before) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) when "defvar" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.defvar(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "defnode" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.defnode(cmd_array[0], cmd_array[1], cmd_array[2]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "mv", "move" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.mv(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) else fail("Command '#{command}' is not supported") end rescue SystemExit,NoMemoryError raise rescue Exception => e fail("Error sending command '#{command}' with params #{cmd_array.inspect}/#{e.message}") end end end end diff --git a/lib/puppet/provider/group/directoryservice.rb b/lib/puppet/provider/group/directoryservice.rb index 97fee883d..e11284898 100644 --- a/lib/puppet/provider/group/directoryservice.rb +++ b/lib/puppet/provider/group/directoryservice.rb @@ -1,26 +1,12 @@ -# Created by Jeff McCune on 2007-07-22 -# Copyright (c) 2007. All rights reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation (version 2 of the License) -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA - require 'puppet/provider/nameservice/directoryservice' Puppet::Type.type(:group).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do desc "Group management using DirectoryService on OS X. " commands :dscl => "/usr/bin/dscl" confine :operatingsystem => :darwin defaultfor :operatingsystem => :darwin has_feature :manages_members end diff --git a/lib/puppet/provider/mcx/mcxcontent.rb b/lib/puppet/provider/mcx/mcxcontent.rb index 3ad437b53..0c0061278 100644 --- a/lib/puppet/provider/mcx/mcxcontent.rb +++ b/lib/puppet/provider/mcx/mcxcontent.rb @@ -1,185 +1,166 @@ -#-- -# Copyright (C) 2008 Jeffrey J McCune. - -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Author: Jeff McCune - require 'tempfile' Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do desc "MCX Settings management using DirectoryService on OS X. This provider manages the entire MCXSettings attribute available to some directory services nodes. This management is 'all or nothing' in that discrete application domain key value pairs are not managed by this provider. It is recommended to use WorkGroup Manager to configure Users, Groups, Computers, or ComputerLists, then use 'ralsh mcx' to generate a puppet manifest from the resulting configuration. Original Author: Jeff McCune (mccune.jeff@gmail.com) " # This provides a mapping of puppet types to DirectoryService # type strings. TypeMap = { :user => "Users", :group => "Groups", :computer => "Computers", :computerlist => "ComputerLists", } class MCXContentProviderException < Exception end commands :dscl => "/usr/bin/dscl" confine :operatingsystem => :darwin defaultfor :operatingsystem => :darwin def self.instances mcx_list = [] TypeMap.keys.each do |ds_type| ds_path = "/Local/Default/#{TypeMap[ds_type]}" output = dscl 'localhost', '-list', ds_path member_list = output.split 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. 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 def self.mcxexport(ds_type, ds_name) ds_t = TypeMap[ds_type] ds_n = ds_name.to_s ds_path = "/Local/Default/#{ds_t}/#{ds_n}" 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_path = "/Local/Default/#{ds_t}/#{ds_name}" tmp = Tempfile.new('puppet_mcx') begin tmp << val tmp.flush dscl 'localhost', '-mcximport', ds_path, tmp.path ensure tmp.close tmp.unlink end end # Given the resource name string, parse ds_type out. def parse_type(name) 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. 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 ds_type end # Given the resource name string, parse ds_name out. def parse_name(name) ds_name = name.split('/')[2] 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. def get_dsparams ds_type = resource[:ds_type] ds_type ||= parse_type(resource[:name]) raise MCXContentProviderException unless TypeMap.keys.include? ds_type.to_sym ds_name = resource[:ds_name] ds_name ||= parse_name(resource[:name]) { :ds_type => ds_type.to_sym, :ds_name => ds_name, } end end diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb index 2e3480985..c1139a679 100644 --- a/lib/puppet/provider/nameservice/directoryservice.rb +++ b/lib/puppet/provider/nameservice/directoryservice.rb @@ -1,548 +1,534 @@ -# Created by Jeff McCune on 2007-07-22 -# Copyright (c) 2007. All rights reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation (version 2 of the License) -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA - require 'puppet' require 'puppet/provider/nameservice' require 'facter/util/plist' require 'cgi' class Puppet::Provider::NameService class DirectoryService < Puppet::Provider::NameService # JJM: Dive into the singleton_class class << self # JJM: This allows us to pass information when calling # Puppet::Type.type # e.g. Puppet::Type.type(:user).provide :directoryservice, :ds_path => "Users" # This is referenced in the get_ds_path class method attr_writer :ds_path attr_writer :macosx_version_major end initvars commands :dscl => "/usr/bin/dscl" commands :dseditgroup => "/usr/sbin/dseditgroup" commands :sw_vers => "/usr/bin/sw_vers" confine :operatingsystem => :darwin defaultfor :operatingsystem => :darwin # JJM 2007-07-25: This map is used to map NameService attributes to their # corresponding DirectoryService attribute names. # See: http://images.apple.com/server/docs.Open_Directory_v10.4.pdf # JJM: Note, this is de-coupled from the Puppet::Type, and must # be actively maintained. There may also be collisions with different # types (Users, Groups, Mounts, Hosts, etc...) @@ds_to_ns_attribute_map = { 'RecordName' => :name, 'PrimaryGroupID' => :gid, 'NFSHomeDirectory' => :home, 'UserShell' => :shell, 'UniqueID' => :uid, 'RealName' => :comment, 'Password' => :password, 'GeneratedUID' => :guid, 'IPAddress' => :ip_address, 'ENetAddress' => :en_address, 'GroupMembership' => :members, } # JJM The same table as above, inverted. @@ns_to_ds_attribute_map = { :name => 'RecordName', :gid => 'PrimaryGroupID', :home => 'NFSHomeDirectory', :shell => 'UserShell', :uid => 'UniqueID', :comment => 'RealName', :password => 'Password', :guid => 'GeneratedUID', :en_address => 'ENetAddress', :ip_address => 'IPAddress', :members => 'GroupMembership', } @@password_hash_dir = "/var/db/shadow/hash" def self.instances # JJM Class method that provides an array of instance objects of this # type. # JJM: Properties are dependent on the Puppet::Type we're managine. type_property_array = [:name] + @resource_type.validproperties # Create a new instance of this Puppet::Type for each object present # on the system. list_all_present.collect do |name_string| self.new(single_report(name_string, *type_property_array)) end end def self.get_ds_path # JJM: 2007-07-24 This method dynamically returns the DS path we're concerned with. # For example, if we're working with an user type, this will be /Users # with a group type, this will be /Groups. # @ds_path is an attribute of the class itself. return @ds_path if defined?(@ds_path) # JJM: "Users" or "Groups" etc ... (Based on the Puppet::Type) # Remember this is a class method, so self.class is Class # Also, @resource_type seems to be the reference to the # Puppet::Type this class object is providing for. @resource_type.name.to_s.capitalize + "s" end def self.get_macosx_version_major return @macosx_version_major if defined?(@macosx_version_major) begin # Make sure we've loaded all of the facts Facter.loadfacts if Facter.value(:macosx_productversion_major) product_version_major = Facter.value(:macosx_productversion_major) else # TODO: remove this code chunk once we require Facter 1.5.5 or higher. Puppet.warning("DEPRECATION WARNING: Future versions of the directoryservice provider will require Facter 1.5.5 or newer.") product_version = Facter.value(:macosx_productversion) fail("Could not determine OS X version from Facter") if product_version.nil? product_version_major = product_version.scan(/(\d+)\.(\d+)./).join(".") end fail("#{product_version_major} is not supported by the directoryservice provider") if %w{10.0 10.1 10.2 10.3}.include?(product_version_major) @macosx_version_major = product_version_major return @macosx_version_major rescue Puppet::ExecutionFailure => detail fail("Could not determine OS X version: #{detail}") end end def self.list_all_present # JJM: List all objects of this Puppet::Type already present on the system. begin dscl_output = execute(get_exec_preamble("-list")) rescue Puppet::ExecutionFailure => detail fail("Could not get #{@resource_type.name} list from DirectoryService") end dscl_output.split("\n") end def self.parse_dscl_url_data(dscl_output) # we need to construct a Hash from the dscl -url output to match # that returned by the dscl -plist output for 10.5+ clients. # # Nasty assumptions: # a) no values *end* in a colon ':', only keys # b) if a line ends in a colon and the next line does start with # a space, then the second line is a value of the first. # c) (implied by (b)) keys don't start with spaces. dscl_plist = {} dscl_output.split("\n").inject([]) do |array, line| if line =~ /^\s+/ # it's a value array[-1] << line # add the value to the previous key else array << line end array end.compact dscl_output.each do |line| # This should be a 'normal' entry. key and value on one line. # We split on ': ' to deal with keys/values with a colon in them. split_array = line.split(/:\s+/) key = split_array.first value = CGI::unescape(split_array.last.strip.chomp) # We need to treat GroupMembership separately as it is currently # the only attribute we care about multiple values for, and # the values can never contain spaces (shortnames) # We also make every value an array to be consistent with the # output of dscl -plist under 10.5 if key == "GroupMembership" dscl_plist[key] = value.split(/\s/) else dscl_plist[key] = [value] end end dscl_plist end def self.parse_dscl_plist_data(dscl_output) Plist.parse_xml(dscl_output) end def self.generate_attribute_hash(input_hash, *type_properties) attribute_hash = {} input_hash.keys.each do |key| ds_attribute = key.sub("dsAttrTypeStandard:", "") next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute]) ds_value = input_hash[key] case @@ds_to_ns_attribute_map[ds_attribute] when :members ds_value = ds_value # only members uses arrays so far when :gid, :uid # OS X stores objects like uid/gid as strings. # Try casting to an integer for these cases to be # consistent with the other providers and the group type # validation begin ds_value = Integer(ds_value[0]) rescue ArgumentError ds_value = ds_value[0] end else ds_value = ds_value[0] end attribute_hash[@@ds_to_ns_attribute_map[ds_attribute]] = ds_value end # NBK: need to read the existing password here as it's not actually # stored in the user record. It is stored at a path that involves the # UUID of the user record for non-Mobile local acccounts. # Mobile Accounts are out of scope for this provider for now attribute_hash[:password] = self.get_password(attribute_hash[:guid]) if @resource_type.validproperties.include?(:password) and Puppet.features.root? attribute_hash end def self.single_report(resource_name, *type_properties) # JJM 2007-07-24: # Given a the name of an object and a list of properties of that # object, return all property values in a hash. # # This class method returns nil if the object doesn't exist # Otherwise, it returns a hash of the object properties. all_present_str_array = list_all_present # NBK: shortcut the process if the resource is missing return nil unless all_present_str_array.include? resource_name dscl_vector = get_exec_preamble("-read", resource_name) begin dscl_output = execute(dscl_vector) rescue Puppet::ExecutionFailure => detail fail("Could not get report. command execution failed.") end # Two code paths is ugly, but until we can drop 10.4 support we don't # have a lot of choice. Ultimately this should all be done using Ruby # to access the DirectoryService APIs directly, but that's simply not # feasible for a while yet. case self.get_macosx_version_major when "10.4" dscl_plist = self.parse_dscl_url_data(dscl_output) when "10.5", "10.6" dscl_plist = self.parse_dscl_plist_data(dscl_output) end self.generate_attribute_hash(dscl_plist, *type_properties) end def self.get_exec_preamble(ds_action, resource_name = nil) # JJM 2007-07-24 # DSCL commands are often repetitive and contain the same positional # arguments over and over. See http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/additionalfeatures/chapter_10_section_9.html # for an example of what I mean. # This method spits out proper DSCL commands for us. # We EXPECT name to be @resource[:name] when called from an instance object. # 10.4 doesn't support the -plist option for dscl, and 10.5 has a # different format for the -url output with objects with spaces in # their values. *sigh*. Use -url for 10.4 in the hope this can be # deprecated one day, and use -plist for 10.5 and higher. case self.get_macosx_version_major when "10.4" command_vector = [ command(:dscl), "-url", "." ] when "10.5", "10.6" command_vector = [ command(:dscl), "-plist", "." ] end # JJM: The actual action to perform. See "man dscl" # Common actiosn: -create, -delete, -merge, -append, -passwd command_vector << ds_action # JJM: get_ds_path will spit back "Users" or "Groups", # etc... Depending on the Puppet::Type of our self. if resource_name command_vector << "/#{get_ds_path}/#{resource_name}" else command_vector << "/#{get_ds_path}" end # JJM: This returns most of the preamble of the command. # e.g. 'dscl / -create /Users/mccune' command_vector end def self.set_password(resource_name, guid, password_hash) password_hash_file = "#{@@password_hash_dir}/#{guid}" begin File.open(password_hash_file, 'w') { |f| f.write(password_hash)} rescue Errno::EACCES => detail fail("Could not write to password hash file: #{detail}") end # NBK: For shadow hashes, the user AuthenticationAuthority must contain a value of # ";ShadowHash;". The LKDC in 10.5 makes this more interesting though as it # will dynamically generate ;Kerberosv5;;username@LKDC:SHA1 attributes if # missing. Thus we make sure we only set ;ShadowHash; if it is missing, and # we can do this with the merge command. This allows people to continue to # use other custom AuthenticationAuthority attributes without stomping on them. # # There is a potential problem here in that we're only doing this when setting # the password, and the attribute could get modified at other times while the # hash doesn't change and so this doesn't get called at all... but # without switching all the other attributes to merge instead of create I can't # see a simple enough solution for this that doesn't modify the user record # every single time. This should be a rather rare edge case. (famous last words) dscl_vector = self.get_exec_preamble("-merge", resource_name) dscl_vector << "AuthenticationAuthority" << ";ShadowHash;" begin dscl_output = execute(dscl_vector) rescue Puppet::ExecutionFailure => detail fail("Could not set AuthenticationAuthority.") end end def self.get_password(guid) password_hash = nil password_hash_file = "#{@@password_hash_dir}/#{guid}" if File.exists?(password_hash_file) and File.file?(password_hash_file) fail("Could not read password hash file at #{password_hash_file}") if not File.readable?(password_hash_file) f = File.new(password_hash_file) password_hash = f.read f.close end 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 # managing and call the method which sets that property value # dscl can't create everything at once unfortunately. if ensure_value == :present @resource.class.validproperties.each do |name| next if name == :ensure # LAK: We use property.sync here rather than directly calling # the settor method because the properties might do some kind # of conversion. In particular, the user gid property might # have a string and need to convert it to a number if @resource.should(name) @resource.property(name).sync elsif value = autogen(name) self.send(name.to_s + "=", value) else next end end end end def password=(passphrase) exec_arg_vector = self.class.get_exec_preamble("-read", @resource.name) exec_arg_vector << @@ns_to_ds_attribute_map[:guid] begin guid_output = execute(exec_arg_vector) guid_plist = Plist.parse_xml(guid_output) # Although GeneratedUID like all DirectoryService values can be multi-valued # according to the schema, in practice user accounts cannot have multiple UUIDs # otherwise Bad Things Happen, so we just deal with the first value. guid = guid_plist["dsAttrTypeStandard:#{@@ns_to_ds_attribute_map[:guid]}"][0] self.class.set_password(@resource.name, guid, passphrase) rescue Puppet::ExecutionFailure => detail fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}") end end # NBK: we override @parent.set as we need to execute a series of commands # to deal with array values, rather than the single command nameservice.rb # expects to be returned by modifycmd. Thus we don't bother defining modifycmd. def set(param, value) self.class.validate(param, value) current_members = @property_value_cache_hash[:members] if param == :members # If we are meant to be authoritative for the group membership # then remove all existing members who haven't been specified # in the manifest. remove_unwanted_members(current_members, value) if @resource[:auth_membership] and not current_members.nil? # if they're not a member, make them one. add_members(current_members, value) else exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name]) # JJM: The following line just maps the NS name to the DS name # e.g. { :uid => 'UniqueID' } exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(param)] # JJM: The following line sends the actual value to set the property to exec_arg_vector << value.to_s begin execute(exec_arg_vector) rescue Puppet::ExecutionFailure => detail fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}") end end end # NBK: we override @parent.create as we need to execute a series of commands # to create objects with dscl, rather than the single command nameservice.rb # expects to be returned by addcmd. Thus we don't bother defining addcmd. def create if exists? info "already exists" return nil end # NBK: First we create the object with a known guid so we can set the contents # of the password hash if required # Shelling out sucks, but for a single use case it doesn't seem worth # requiring people install a UUID library that doesn't come with the system. # This should be revisited if Puppet starts managing UUIDs for other platform # user records. guid = %x{/usr/bin/uuidgen}.chomp exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name]) exec_arg_vector << @@ns_to_ds_attribute_map[:guid] << guid begin execute(exec_arg_vector) rescue Puppet::ExecutionFailure => detail fail("Could not set GeneratedUID for #{@resource.class.name} #{@resource.name}: #{detail}") end if value = @resource.should(:password) and value != "" self.class.set_password(@resource[:name], guid, value) end # Now we create all the standard properties Puppet::Type.type(@resource.class.name).validproperties.each do |property| next if property == :ensure 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 exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name]) exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(property)] next if property == :password # skip setting the password here exec_arg_vector << value.to_s begin execute(exec_arg_vector) rescue Puppet::ExecutionFailure => detail fail("Could not create #{@resource.class.name} #{@resource.name}: #{detail}") end end end end end def remove_unwanted_members(current_members, new_members) current_members.each do |member| if not new_members.flatten.include?(member) cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-d", member, @resource[:name]] begin execute(cmd) rescue Puppet::ExecutionFailure => detail fail("Could not remove #{member} from group: #{@resource.name}, #{detail}") end end end end def add_members(current_members, new_members) new_members.flatten.each do |new_member| if current_members.nil? or not current_members.include?(new_member) cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-a", new_member, @resource[:name]] begin execute(cmd) rescue Puppet::ExecutionFailure => detail fail("Could not add #{new_member} to group: #{@resource.name}, #{detail}") end end end end def deletecmd # JJM: Like addcmd, only called when deleting the object itself # Note, this isn't used to delete properties of the object, # at least that's how I understand it... self.class.get_exec_preamble("-delete", @resource[:name]) end def getinfo(refresh = false) # JJM 2007-07-24: # Override the getinfo method, which is also defined in nameservice.rb # This method returns and sets @infohash # I'm not re-factoring the name "getinfo" because this method will be # most likely called by nameservice.rb, which I didn't write. if refresh or (! defined?(@property_value_cache_hash) or ! @property_value_cache_hash) # JJM 2007-07-24: OK, there's a bit of magic that's about to # happen... Let's see how strong my grip has become... =) # # self is a provider instance of some Puppet::Type, like # Puppet::Type::User::ProviderDirectoryservice for the case of the # user type and this provider. # # self.class looks like "user provider directoryservice", if that # helps you ... # # self.class.resource_type is a reference to the Puppet::Type class, # probably Puppet::Type::User or Puppet::Type::Group, etc... # # self.class.resource_type.validproperties is a class method, # returning an Array of the valid properties of that specific # Puppet::Type. # # So... something like [:comment, :home, :password, :shell, :uid, # :groups, :ensure, :gid] # # Ultimately, we add :name to the list, delete :ensure from the # list, then report on the remaining list. Pretty whacky, ehh? type_properties = [:name] + self.class.resource_type.validproperties type_properties.delete(:ensure) if type_properties.include? :ensure type_properties << :guid # append GeneratedUID so we just get the report here @property_value_cache_hash = self.class.single_report(@resource[:name], *type_properties) [:uid, :gid].each do |param| @property_value_cache_hash[param] = @property_value_cache_hash[param].to_i if @property_value_cache_hash and @property_value_cache_hash.include?(param) end end @property_value_cache_hash end end end diff --git a/lib/puppet/provider/package/pkgdmg.rb b/lib/puppet/provider/package/pkgdmg.rb index 39e377d66..662d05c8f 100644 --- a/lib/puppet/provider/package/pkgdmg.rb +++ b/lib/puppet/provider/package/pkgdmg.rb @@ -1,144 +1,127 @@ # -# pkgdmg.rb -# -# Install Installer.app packages wrapped up inside a DMG image file. -# -# Copyright (C) 2007 Jeff McCune Jeff McCune -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation (version 2 of the License) -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA -# # Motivation: DMG files provide a true HFS file system # and are easier to manage and .pkg bundles. # # Note: the 'apple' Provider checks for the package name # in /L/Receipts. Since we install multiple pkg's from a single # source, we treat the source .pkg.dmg file as the package name. # As a result, we store installed .pkg.dmg file names # in /var/db/.puppet_pkgdmg_installed_ require 'puppet/provider/package' require 'facter/util/plist' Puppet::Type.type(:package).provide :pkgdmg, :parent => Puppet::Provider::Package do desc "Package management based on Apple's Installer.app and DiskUtility.app. This package works by checking the contents of a DMG image for Apple pkg or mpkg files. Any number of pkg or mpkg files may exist in the root directory of the DMG file system. Sub directories are not checked for packages. See `the wiki docs ` for more detail." confine :operatingsystem => :darwin defaultfor :operatingsystem => :darwin commands :installer => "/usr/sbin/installer" commands :hdiutil => "/usr/bin/hdiutil" commands :curl => "/usr/bin/curl" # JJM We store a cookie for each installed .pkg.dmg in /var/db def self.instance_by_name Dir.entries("/var/db").find_all { |f| f =~ /^\.puppet_pkgdmg_installed_/ }.collect do |f| name = f.sub(/^\.puppet_pkgdmg_installed_/, '') yield name if block_given? name end end def self.instances instance_by_name.collect do |name| new( :name => name, :provider => :pkgdmg, :ensure => :installed ) end end def self.installpkg(source, name, orig_source) installer "-pkg", source, "-target", "/" # Non-zero exit status will throw an exception. File.open("/var/db/.puppet_pkgdmg_installed_#{name}", "w") do |t| t.print "name: '#{name}'\n" t.print "source: '#{orig_source}'\n" end end def self.installpkgdmg(source, name) unless source =~ /\.dmg$/i || source =~ /\.pkg$/i raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file") end require 'open-uri' cached_source = source if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source cached_source = "/tmp/#{name}" begin curl "-o", cached_source, "-C", "-", "-k", "-s", "--url", source Puppet.debug "Success: curl transfered [#{name}]" rescue Puppet::ExecutionFailure Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods." cached_source = source end end begin if source =~ /\.dmg$/i File.open(cached_source) do |dmg| xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", dmg.path hdiutil_info = Plist::parse_xml(xml_str) raise Puppet::Error.new("No disk entities returned by mount at #{dmg.path}") unless hdiutil_info.has_key?("system-entities") mounts = hdiutil_info["system-entities"].collect { |entity| entity["mount-point"] }.compact begin mounts.each do |mountpoint| Dir.entries(mountpoint).select { |f| f =~ /\.m{0,1}pkg$/i }.each do |pkg| installpkg("#{mountpoint}/#{pkg}", name, source) end end ensure mounts.each do |mountpoint| hdiutil "eject", mountpoint end end end elsif source =~ /\.pkg$/i installpkg(cached_source, name, source) else raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file") end ensure # JJM Remove the file if open-uri didn't already do so. File.unlink(cached_source) if File.exist?(cached_source) end end def query if FileTest.exists?("/var/db/.puppet_pkgdmg_installed_#{@resource[:name]}") Puppet.debug "/var/db/.puppet_pkgdmg_installed_#{@resource[:name]} found" return {:name => @resource[:name], :ensure => :present} else return nil end end def install source = nil unless source = @resource[:source] raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package source.") end unless name = @resource[:name] raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package name.") end self.class.installpkgdmg(source,name) end end diff --git a/lib/puppet/provider/user/directoryservice.rb b/lib/puppet/provider/user/directoryservice.rb index 4b62a6ae7..a2c561039 100644 --- a/lib/puppet/provider/user/directoryservice.rb +++ b/lib/puppet/provider/user/directoryservice.rb @@ -1,100 +1,86 @@ -# Created by Jeff McCune on 2007-07-22 -# Copyright (c) 2007. All rights reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation (version 2 of the License) -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston MA 02110-1301 USA - require 'puppet/provider/nameservice/directoryservice' Puppet::Type.type(:user).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do desc "User management using DirectoryService on OS X." commands :dscl => "/usr/bin/dscl" confine :operatingsystem => :darwin defaultfor :operatingsystem => :darwin # JJM: DirectoryService can manage passwords. # This needs to be a special option to dscl though (-passwd) has_feature :manages_passwords # JJM: comment matches up with the /etc/passwd concept of an user options :comment, :key => "realname" options :password, :key => "passwd" autogen_defaults :home => "/var/empty", :shell => "/usr/bin/false" verify :gid, "GID must be an integer" do |value| value.is_a? Integer end verify :uid, "UID must be an integer" do |value| value.is_a? Integer end def autogen_comment @resource[:name].capitalize end # The list of all groups the user is a member of. # JJM: FIXME: Override this method... def groups groups = [] groups.join(",") end # This is really lame. We have to iterate over each # of the groups and add us to them. def groups=(groups) # case groups # when Fixnum # groups = [groups.to_s] # when String # groups = groups.split(/\s*,\s*/) # else # raise Puppet::DevError, "got invalid groups value #{groups.class} of type #{groups}" # end # # Get just the groups we need to modify # diff = groups - (@is || []) # # data = {} # open("| #{command(:nireport)} / /groups name users") do |file| # file.each do |line| # name, members = line.split(/\s+/) # # if members.nil? or members =~ /NoValue/ # data[name] = [] # else # # Add each diff group's current members # data[name] = members.split(/,/) # end # end # end # # user = @resource[:name] # data.each do |name, members| # if members.include? user and groups.include? name # # I'm in the group and should be # next # elsif members.include? user # # I'm in the group and shouldn't be # setuserlist(name, members - [user]) # elsif groups.include? name # # I'm not in the group and should be # setuserlist(name, members + [user]) # else # # I'm not in the group and shouldn't be # next # end # end end end diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb index a8fb1f15f..f4d3c43e1 100644 --- a/lib/puppet/type/augeas.rb +++ b/lib/puppet/type/augeas.rb @@ -1,182 +1,178 @@ -#-- -# Copyright (C) 2008 Red Hat Inc. # -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. +# Copyright 2011 Bryan Kearney # -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# http://www.apache.org/licenses/LICENSE-2.0 # -# Author: Bryan Kearney +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. Puppet::Type.newtype(:augeas) do include Puppet::Util feature :parse_commands, "Parse the command string" feature :need_to_run?, "If the command should run" feature :execute_changes, "Actually make the changes" @doc = "Apply the changes (single or array of changes) to the filesystem via the augeas tool. Requires: - augeas to be installed (http://www.augeas.net) - ruby-augeas bindings Sample usage with a string: augeas{\"test1\" : context => \"/files/etc/sysconfig/firstboot\", changes => \"set RUN_FIRSTBOOT YES\", onlyif => \"match other_value size > 0\", } Sample usage with an array and custom lenses: augeas{\"jboss_conf\": context => \"/files\", changes => [ \"set /etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress\", \"set /etc/jbossas/jbossas.conf/JAVA_HOME /usr\" ], load_path => \"$/usr/share/jbossas/lenses\", } " newparam (:name) do desc "The name of this task. Used for uniqueness" isnamevar end newparam (:context) do desc "Optional context path. This value is prepended to the paths of all changes if the path is relative. If INCL is set, defaults to '/files' + INCL, otherwise the empty string" defaultto "" munge do |value| if value.empty? and resource[:incl] "/files" + resource[:incl] else value end end end newparam (:onlyif) do desc "Optional augeas command and comparisons to control the execution of this type. Supported onlyif syntax: get [AUGEAS_PATH] [COMPARATOR] [STRING] match [MATCH_PATH] size [COMPARATOR] [INT] match [MATCH_PATH] include [STRING] match [MATCH_PATH] not_include [STRING] match [MATCH_PATH] == [AN_ARRAY] match [MATCH_PATH] != [AN_ARRAY] 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 newparam(:changes) do desc "The changes which should be applied to the filesystem. This can be either a string which contains a command or an array of commands. Commands supported are: set [PATH] [VALUE] Sets the value VALUE at loction PATH 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 newparam(:root) do desc "A file system path; all files loaded by Augeas are loaded underneath ROOT" defaultto "/" end newparam(:load_path) do desc "Optional colon separated list of directories; these directories are searched for schema definitions" defaultto "" end newparam(:force) do desc "Optional command to force the augeas type to execute even if it thinks changes will not be made. This does not overide the only setting. If onlyif is set, then the foce setting will not override that result" defaultto false end newparam(:type_check) do desc "Set to true if augeas should perform typechecking. Optional, defaults to false" newvalues(:true, :false) defaultto :false end newparam(:lens) do desc "Use a specific lens, e.g. `Hosts.lns`. When this parameter is set, you must also set the incl parameter to indicate which file to load. Only that file will be loaded, which greatly speeds up execution of the type" 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." end validate do has_lens = !self[:lens].nil? has_incl = !self[:incl].nil? self.fail "You must specify both the lens and incl parameters, or neither" if has_lens != has_incl end # This is the acutal meat of the code. It forces # augeas to be run and fails or not based on the augeas return # code. newproperty(:returns) do |property| include Puppet::Util desc "The expected return code from the augeas command. Should not be set" defaultto 0 # Make output a bit prettier def change_to_s(currentvalue, newvalue) "executed successfully" end # if the onlyif resource is provided, then the value is parsed. # a return value of 0 will stop exection because it matches the # default value. def retrieve if @resource.provider.need_to_run?() :need_to_run else 0 end end # Actually execute the command. def sync @resource.provider.execute_changes end end end diff --git a/lib/puppet/type/mcx.rb b/lib/puppet/type/mcx.rb index 07c9348dd..d0306ca46 100644 --- a/lib/puppet/type/mcx.rb +++ b/lib/puppet/type/mcx.rb @@ -1,118 +1,99 @@ -#-- -# Copyright (C) 2008 Jeffrey J McCune. - -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Author: Jeff McCune - Puppet::Type.newtype(:mcx) do @doc = "MCX object management using DirectoryService on OS X. The default provider of this type merely manages the XML plist as reported by the dscl -mcxexport command. This is similar to the content property of the file type in Puppet. The recommended method of using this type is to use Work Group Manager to manage users and groups on the local computer, record the resulting puppet manifest using the command `puppet resource mcx`, then deploy it to other machines. **Autorequires:** If Puppet is managing the user, group, or computer that these MCX settings refer to, the MCX resource will autorequire that user, group, or computer. " feature :manages_content, \ "The provider can manage MCXSettings as a string.", :methods => [:content, :content=] ensurable do desc "Create or remove the MCX setting." newvalue(:present) do provider.create end newvalue(:absent) do provider.destroy end end newparam(:name) do desc "The name of the resource being managed. The default naming convention follows Directory Service paths: /Computers/localhost /Groups/admin /Users/localadmin The `ds_type` and `ds_name` type parameters are not necessary if the default naming convention is followed." isnamevar end newparam(:ds_type) do desc "The DirectoryService type this MCX setting attaches to." newvalues(:user, :group, :computer, :computerlist) end newparam(:ds_name) do desc "The name to attach the MCX Setting to. e.g. 'localhost' when ds_type => computer. This setting is not required, as it may be parsed so long as the resource name is parseable. e.g. /Groups/admin where 'group' is the dstype." end 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_name - + Note that `ds_type` is capitalized and plural in the dscl command." end # JJM Yes, this is not DRY at all. Because of the code blocks # autorequire must be done this way. I think. def setup_autorequire(type) # value returns a Symbol name = value(:name) ds_type = value(:ds_type) ds_name = value(:ds_name) if ds_type == type rval = [ ds_name.to_s ] else rval = [ ] end rval end autorequire(:user) do setup_autorequire(:user) end autorequire(:group) do setup_autorequire(:group) end autorequire(:computer) do setup_autorequire(:computer) end end diff --git a/spec/unit/provider/mcx/mcxcontent_spec.rb b/spec/unit/provider/mcx/mcxcontent_spec.rb index 1189143f3..27aae6807 100755 --- a/spec/unit/provider/mcx/mcxcontent_spec.rb +++ b/spec/unit/provider/mcx/mcxcontent_spec.rb @@ -1,175 +1,157 @@ #! /usr/bin/env ruby -#-- -# Copyright (C) 2008 Jeffrey J McCune. - -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Author: Jeff McCune require 'spec_helper' provider_class = Puppet::Type.type(:mcx).provider(:mcxcontent) # describe creates a new ExampleGroup object. describe provider_class do # :each executes before each test. # :all executes once for the test group and before :each. before :each do # Create a mock resource @resource = stub 'resource' @provider = provider_class.new @attached_to = "/Users/foobar" @ds_path = "/Local/Default/Users/foobar" # A catch all; no parameters set @resource.stubs(:[]).returns(nil) # But set name, ensure and enable @resource.stubs(:[]).with(:name).returns @attached_to @resource.stubs(:[]).with(:ensure).returns :present @resource.stubs(:ref).returns "Mcx[#{@attached_to}]" # stub out the provider methods that actually touch the filesystem # or execute commands @provider.class.stubs(:execute).returns('') @provider.stubs(:execute).returns('') @provider.stubs(:resource).returns @resource end it "should have a create method." do @provider.should respond_to(:create) end it "should have a destroy method." do @provider.should respond_to(:destroy) end it "should have an exists? method." do @provider.should respond_to(:exists?) end it "should have an content method." do @provider.should respond_to(:content) end it "should have an content= method." do @provider.should respond_to(:content=) end describe "when managing the resource" do it "should execute external command dscl from :create" do @provider.class.expects(:dscl).returns('').once @provider.create end it "should execute external command dscl from :destroy" do @provider.class.expects(:dscl).with('localhost', '-mcxdelete', @ds_path).returns('').once @provider.destroy end it "should execute external command dscl from :exists?" do @provider.class.expects(:dscl).with('localhost', '-mcxexport', @ds_path).returns('').once @provider.exists? end it "should execute external command dscl from :content" do @provider.class.expects(:dscl).with('localhost', '-mcxexport', @ds_path).returns('') @provider.content end it "should execute external command dscl from :content=" do @provider.class.expects(:dscl).returns('') @provider.content='' end end describe "when creating and parsing the name for ds_type" do before :each do @resource.stubs(:[]).with(:name).returns "/Foo/bar" end it "should not accept /Foo/bar" do lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should accept /Foo/bar with ds_type => user" do @resource.stubs(:[]).with(:ds_type).returns "user" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept /Foo/bar with ds_type => group" do @resource.stubs(:[]).with(:ds_type).returns "group" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept /Foo/bar with ds_type => computer" do @resource.stubs(:[]).with(:ds_type).returns "computer" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :name => /Foo/bar with ds_type => computerlist" do @resource.stubs(:[]).with(:ds_type).returns "computerlist" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end end describe "when creating and :name => foobar" do before :each do @resource.stubs(:[]).with(:name).returns "foobar" end it "should not accept unspecified :ds_type and :ds_name" do lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should not accept unspecified :ds_type" do @resource.stubs(:[]).with(:ds_type).returns "user" lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should not accept unspecified :ds_name" do @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should raise_error(MCXContentProviderException) end it "should accept :ds_type => user, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "user" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :ds_type => group, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "group" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :ds_type => computer, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "computer" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should accept :ds_type => computerlist, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "computerlist" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should_not raise_error(MCXContentProviderException) end it "should not accept :ds_type => bogustype, ds_name => foo" do @resource.stubs(:[]).with(:ds_type).returns "bogustype" @resource.stubs(:[]).with(:ds_name).returns "foo" lambda { @provider.create }.should raise_error(MCXContentProviderException) end end describe "when gathering existing instances" do it "should define an instances class method." do @provider.class.should respond_to(:instances) end it "should call external command dscl -list /Local/Default/ on each known ds_type" do @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Users").returns('') @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Groups").returns('') @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/Computers").returns('') @provider.class.expects(:dscl).with('localhost', '-list', "/Local/Default/ComputerLists").returns('') @provider.class.instances end end end diff --git a/spec/unit/type/mcx_spec.rb b/spec/unit/type/mcx_spec.rb index aaf2d567e..b35355a29 100755 --- a/spec/unit/type/mcx_spec.rb +++ b/spec/unit/type/mcx_spec.rb @@ -1,100 +1,80 @@ #!/usr/bin/env ruby -#-- -# Copyright (C) 2008 Jeffrey J McCune. - -# This program and entire repository is free software; you can -# redistribute it and/or modify it under the terms of the GNU -# General Public License as published by the Free Software -# Foundation; either version 2 of the License, or any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -# Author: Jeff McCune - -# Most of this code copied from /spec/type/service.rb require 'spec_helper' require 'puppet/type/mcx' mcx_type = Puppet::Type.type(:mcx) describe mcx_type, "when validating attributes" do properties = [:ensure, :content] parameters = [:name, :ds_type, :ds_name] parameters.each do |p| it "should have a #{p} parameter" do mcx_type.attrclass(p).ancestors.should be_include(Puppet::Parameter) end it "should have documentation for its #{p} parameter" do mcx_type.attrclass(p).doc.should be_instance_of(String) end end properties.each do |p| it "should have a #{p} property" do mcx_type.attrclass(p).ancestors.should be_include(Puppet::Property) end it "should have documentation for its #{p} property" do mcx_type.attrclass(p).doc.should be_instance_of(String) end end end describe mcx_type, "default values" do before :each do provider_class = mcx_type.provider(mcx_type.providers[0]) mcx_type.stubs(:defaultprovider).returns provider_class end it "should be nil for :ds_type" do mcx_type.new(:name => '/Foo/bar')[:ds_type].should be_nil end it "should be nil for :ds_name" do mcx_type.new(:name => '/Foo/bar')[:ds_name].should be_nil end it "should be nil for :content" do mcx_type.new(:name => '/Foo/bar')[:content].should be_nil end end describe mcx_type, "when validating properties" do before :each do provider_class = mcx_type.provider(mcx_type.providers[0]) mcx_type.stubs(:defaultprovider).returns provider_class end it "should be able to create an instance" do lambda { mcx_type.new(:name => '/Foo/bar') }.should_not raise_error end it "should support :present as a value to :ensure" do lambda { mcx_type.new(:name => "/Foo/bar", :ensure => :present) }.should_not raise_error end it "should support :absent as a value to :ensure" do lambda { mcx_type.new(:name => "/Foo/bar", :ensure => :absent) }.should_not raise_error end end diff --git a/test/test b/test/test index c8b9b08ef..8d2659cb7 100755 --- a/test/test +++ b/test/test @@ -1,241 +1,241 @@ #!/usr/bin/env ruby # # = Synopsis # # Run unit tests, usually with the goal of resolving some conflict # between tests. # # = Usage # # test [-d|--debug] [-f|--files] [-h|--help] [-n method] [-v|--verbose] [file] ... # # = Description # # This script is useful for running a specific subset of unit tests, especially # when attempting to find a conflict between tests. By default, it will take # the first argument you pass it and run that test or test directory with each # test directory in turn, looking for a failure. If any tests fail, then # the script will drill into that test directory, looking for the specific conflict. # # In this way, when you have deduced you have two conflicting unit tests (tests which # pass in isolation but fail when run together), you can tell this script where # the failure is and leave it alone to find the conflict. # # This script is different from the Rakefile because it will run all tests in # a single process, whereas if you ask the Rakefile to run multiple tests, it will # run them in separate processes thus making it impossible to find conflicts. # # = Examples # # Attempt to resolve a conflict between a single test suite that could be anywhere: # # ./test ral/providers/user.rb # # Determine whether two individual files conflict: # # ./test --files language/functions.rb ral/providers/provider.rb # # Run the same test, but only run a specific unit test: # # ./test -d -n test_search --files language/functions.rb ral/providers/provider.rb # # = Options # # debug:: # Enable full debugging. # # files:: # Specify exactly which files to test. # # help:: # Print this help message # # n:: # Specify a single unit test to run. You can still specify as many files # as you want. # # verbose:: # Print extra information. # # = Example # # puppet -l /tmp/script.log script.pp # # = Author # # Luke Kanies # # = Copyright # -# Copyright (c) 2005 Puppet Labs, LLC -# Licensed under the GNU Public License +# Copyright (c) 2005-2011 Puppet Labs, LLC +# Licensed under the Apache 2.0 License require 'find' require 'getoptlong' include Find result = GetoptLong.new( [ "--debug", "-d", GetoptLong::NO_ARGUMENT ], [ "--verbose", "-v", GetoptLong::NO_ARGUMENT ], [ "-n", GetoptLong::REQUIRED_ARGUMENT ], [ "--files", "-f", GetoptLong::NO_ARGUMENT ], [ "--help", "-h", GetoptLong::NO_ARGUMENT ] ) usage = "USAGE: %s [--help] suite" % $0 $options = {} keep = [] result.each { |opt,arg| case opt when "--verbose" $options[:verbose] = true when "--files" $options[:files] = true when "--debug" $options[:debug] = true $options[:verbose] = true when "--help" puts usage exit else keep << opt keep << arg if arg end } def dirs Dir.glob("*").find_all { |d| FileTest.directory?(d) }.reject { |d| ["lib", "data"].include?(d) } end def rake(*args) print "trying %s..." % args.join(" ") output = %x{rake %s} % args.join(" ") if $?.exitstatus == 0 puts "succeeded" return true else puts "failed" return false end end def resolve(dir) dirs = dirs() # If the passed dir is a subdir or file, put the basedir last if dir.include?(File::SEPARATOR) basedir = dir.split(File::SEPARATOR)[0] if dirs.include?(basedir) dirs.delete(basedir) dirs << basedir end end failed = nil dirs.each do |d| next if d == dir unless run([d, dir]) failed = d break end end puts "%s failed" % failed files = ruby_files(failed) files.each do |file| unless run([file, dir]) puts file exit(0) end end exit(1) end def ruby_files(dir) files = [] # First collect the entire file list. begin find(dir) { |f| files << f if f =~ /\.rb$/ } rescue => detail puts "could not find on %s: %s" % [dir.inspect, detail] end files end def run(files, flags = nil) args = %w{ruby} args << "-Ilib:../lib" args << "lib/rake/puppet_test_loader.rb" if flags args += flags end args += ARGV print files.join(" ") + "... " $stdout.flush files.each do |file| case File.stat(file).ftype when "file"; args << file when "directory"; args += ruby_files(file) else $stderr.puts "Skipping %s; can't handle %s" % [file, File.stat(file).ftype] end end args = args.join(" ") if $options[:verbose] p args end output = %x{#{args} 2>&1} if $options[:debug] print output end if $?.exitstatus == 0 puts "succeeded" return true else puts "failed" puts output return false end end if $options[:files] run(ARGV, keep) else dir = ARGV.shift unless dir $stderr.puts usage exit(1) end resolve(dir) end # # #files = [] # #args.each do |test| # if FileTest.directory?(test) # files += ruby_files(test) # end #end ## Now load all of our files. #files.each do |file| # load file unless file =~ /^-/ #end # #runner = Test::Unit::AutoRunner.new(false) #runner.process_args #runner.run