diff --git a/CHANGELOG b/CHANGELOG index 346577be8..290a8c94f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,910 +1,913 @@ + 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/lib/puppet/external/nagios.rb b/lib/puppet/external/nagios.rb new file mode 100755 index 000000000..78459fcb6 --- /dev/null +++ b/lib/puppet/external/nagios.rb @@ -0,0 +1,50 @@ +#!/usr/local/bin/ruby -w + +#-------------------- +# A script to retrieve hosts from ldap and create an importable +# cfservd file from them +# +# $Id: nagios.rb,v 1.3 2004/06/09 20:32:46 luke Exp $ + +require 'digest/md5' +#require 'ldap' +require 'puppet/external/nagios/parser.rb' +require 'puppet/external/nagios/base.rb' + +module Nagios + NAGIOSVERSION = '1.1' + # yay colors + PINK = "" + GREEN = "" + YELLOW = "" + SLATE = "" + ORANGE = "" + BLUE = "" + NOCOLOR = "" + RESET = "" + + def self.version + NAGIOSVERSION + end + + class Config + def Config.import(config) + + text = String.new + + File.open(config) { |file| + file.each { |line| + text += line + } + } + parser = Nagios::Parser.new + return parser.parse(text) + end + + def Config.each + Nagios::Object.objects.each { |object| + yield object + } + end + end +end diff --git a/lib/puppet/external/nagios/base.rb b/lib/puppet/external/nagios/base.rb new file mode 100755 index 000000000..efc3982b4 --- /dev/null +++ b/lib/puppet/external/nagios/base.rb @@ -0,0 +1,421 @@ +# The base class for all of our Nagios object types. Everything else +# is mostly just data. +class Nagios::Base + + class UnknownNagiosType < RuntimeError # When an unknown type is asked for by name. + end + + include Enumerable + + class << self + attr_accessor :parameters, :derivatives, :ocs, :name, :att + attr_accessor :ldapbase + + attr_writer :namevar + + attr_reader :superior + end + + # Attach one class to another. + def self.attach(hash) + @attach ||= {} + hash.each do |n, v| @attach[n] = v end + end + + # Convert a parameter to camelcase + def self.camelcase(param) + param.gsub(/_./) do |match| + match.sub(/_/,'').capitalize + end + end + + # Uncamelcase a parameter. + def self.decamelcase(param) + param.gsub(/[A-Z]/) do |match| + "_" + match.downcase + end + end + + # Create a new instance of a given class. + def self.create(name, args = {}) + name = name.intern if name.is_a? String + + if @types.include?(name) + @types[name].new(args) + else + raise UnknownNagiosType, "Unknown type %s" % name + end + end + + # Yield each type in turn. + def self.eachtype + @types.each do |name, type| + yield [name, type] + end + end + + # Create a mapping. + def self.map(hash) + @map ||= {} + hash.each do |n, v| @map[n] = v end + end + + # Return a mapping (or nil) for a param + def self.mapping(name) + name = name.intern if name.is_a? String + if defined? @map + @map[name] + else + nil + end + end + + # Return the namevar for the canonical name. + def self.namevar + if defined? @namevar + return @namevar + else + if parameter?(:name) + return :name + elsif tmp = (self.name.to_s + "_name").intern and parameter?(tmp) + @namevar = tmp + return @namevar + else + raise "Type %s has no name var" % self.name + end + end + end + + # Create a new type. + def self.newtype(name, &block) + name = name.intern if name.is_a? String + + @types ||= {} + + # Create the class, with the correct name. + t = Class.new(self) + t.name = name + + # Everyone gets this. There should probably be a better way, and I + # should probably hack the attribute system to look things up based on + # this "use" setting, but, eh. + t.parameters = [:use] + + const_set(name.to_s.capitalize,t) + + # Evaluate the passed block. This should usually define all of the work. + t.class_eval(&block) + + @types[name] = t + end + + # Define both the normal case and camelcase method for a parameter + def self.paramattr(name) + camel = camelcase(name) + param = name + + [name, camel].each do |method| + define_method(method) do + @parameters[param] + end + + define_method(method.to_s + "=") do |value| + @parameters[param] = value + end + end + + end + + # Is the specified name a valid parameter? + def self.parameter?(name) + name = name.intern if name.is_a? String + return @parameters.include?(name) + end + + # Manually set the namevar + def self.setnamevar(name) + name = name.intern if name.is_a? String + @namevar = name + end + + # Set the valid parameters for this class + def self.setparameters(*array) + @parameters += array + end + + # Set the superior ldap object class. Seems silly to include this + # in this class, but, eh. + def self.setsuperior(name) + @superior = name + end + + # Parameters to suppress in output. + def self.suppress(name) + @suppress ||= [] + @suppress << name + end + + # Whether a given parameter is suppressed. + def self.suppress?(name) + defined? @suppress and @suppress.include?(name) + end + + # Return our name as the string. + def self.to_s + self.name.to_s + end + + # Return a type by name. + def self.type(name) + name = name.intern if name.is_a? String + + @types[name] + end + + # Convenience methods. + def [](param) + send(param) + end + + # Convenience methods. + def []=(param,value) + send(param.to_s + "=", value) + end + + # Iterate across all ofour set parameters. + def each + @parameters.each { |param,value| + yield(param,value) + } + end + + # Initialize our object, optionally with a list of parameters. + def initialize(args = {}) + @parameters = {} + + args.each { |param,value| + self[param] = value + } + end + + # Handle parameters like attributes. + def method_missing(mname, *args) + pname = mname.to_s + pname.sub!(/=/, '') + + if self.class.parameter?(pname) + if pname =~ /A-Z/ + pname = self.class.decamelcase(pname) + end + self.class.paramattr(pname) + + # Now access the parameters directly, to make it at least less + # likely we'll end up in an infinite recursion. + if mname.to_s =~ /=$/ + @parameters[pname] = *args + else + return @parameters[mname] + end + else + super + end + end + + # Retrieve our name, through a bit of redirection. + def name + send(self.class.namevar) + end + + # This is probably a bad idea. + def name=(value) + send(self.class.namevar.to_s + "=", value) + end + + def namevar + return (self.type + "_name").intern + end + + def parammap(param) + unless defined? @map + map = { + self.namevar => "cn" + } + if self.class.map + map.update(self.class.map) + end + end + if map.include?(param) + return map[param] + else + return "nagios-" + param.id2name.gsub(/_/,'-') + end + end + + def parent + unless defined? self.class.attached + puts "Duh, you called parent on an unattached class" + return + end + + klass,param = self.class.attached + unless @parameters.include?(param) + puts "Huh, no attachment param" + return + end + klass[@parameters[param]] + end + + # okay, this sucks + # how do i get my list of ocs? + def to_ldif + base = self.class.ldapbase + str = self.dn + "\n" + ocs = Array.new + if self.class.ocs + # i'm storing an array, so i have to flatten it and stuff + kocs = self.class.ocs + ocs.push(*kocs) + end + ocs.push "top" + oc = self.class.to_s + oc.sub!(/Nagios/,'nagios') + oc.sub!(/::/,'') + ocs.push oc + ocs.each { |oc| + str += "objectclass: " + oc + "\n" + } + @parameters.each { |name,value| + if self.class.suppress.include?(name) + next + end + ldapname = self.parammap(name) + str += ldapname + ": " + value + "\n" + } + str += "\n" + str + end + + def to_s + str = "define #{self.type} {\n" + + self.each { |param,value| + str += %{\t%-30s %s\n} % [ param, + if value.is_a? Array + value.join(",") + else + value + end + ] + } + + str += "}\n" + + str + end + + # The type of object we are. + def type + self.class.name + end + + # object types + newtype :command do + setparameters :command_name, :command_line + end + + newtype :contact do + setparameters :contact_name, :alias, :host_notification_period, + :host_notification_commands, :service_notification_period, + :service_notification_commands, + :email, :pager, :service_notification_options, :host_notification_options + + setsuperior "person" + end + + newtype :contactgroup do + setparameters :contactgroup_name, :alias, :members + end + + newtype :host do + setparameters :host_name, :notifications_enabled, :event_handler_enabled, + :flap_detection_enabled, :process_perf_data, :retain_status_information, + :retain_nonstatus_information, :register, :use, :alias, + :address, :check_command, :max_check_attempts, :notification_interval, + :notification_period, :notification_options, :checks_enabled, + :failure_prediction_enabled, :parents + + setsuperior "person" + + map :address => "ipHostNumber" + end + + newtype :hostextinfo do + auxiliary = true + + setparameters :host_name, :notes_url, :icon_image, :icon_image_alt, :vrml_image, + "2d_coords".intern, "3d_coords".intern + + setnamevar :host_name + end + + newtype :hostgroup do + setparameters :hostgroup_name, :alias, :contact_groups, :members + end + + newtype :hostgroupescalation do + auxiliary = true + setparameters :hostgroup_name, :first_notification, :last_notification, + :contact_groups, :notification_interval + + setnamevar :hostgroup_name + end + + newtype :service do + attach :host => :host_name + setparameters :name, :active_checks_enabled, :passive_checks_enabled, + :parallelize_check, :obsess_over_service, :check_freshness, + :notifications_enabled, :event_handler_enabled, + :flap_detection_enabled, :process_perf_data, + :retain_status_information, :retain_nonstatus_information, :register, + :is_volatile, :check_period, :max_check_attempts, + :normal_check_interval, :retry_check_interval, :contact_groups, + :notification_interval, :notification_period, :notification_options, + :service_description, :host_name, :freshness_threshold, + :check_command + + suppress :host_name + + setnamevar :service_description + end + + newtype :servicedependency do + auxiliary = true + setparameters :host_name, :service_description, :dependent_host_name, + :dependent_service_description, :execution_failure_criteria, + :notification_failure_criteria + + setnamevar :host_name + end + + newtype :serviceescalation do + setparameters :host_name, :service_description, :first_notification, + :last_notification, :contact_groups, :notification_interval + + setnamevar :host_name + end + + newtype :serviceextinfo do + auxiliary = true + + setparameters :host_name, :service_description, :icon_image, :icon_image_alt + + setnamevar :host_name + end + + newtype :timeperiod do + setparameters :timeperiod_name, :alias, :sunday, :monday, :tuesday, :wednesday, + :thursday, :friday, :saturday + end +end + +# $Id$ diff --git a/lib/puppet/external/nagios/grammar.ry b/lib/puppet/external/nagios/grammar.ry new file mode 100644 index 000000000..f50818f1a --- /dev/null +++ b/lib/puppet/external/nagios/grammar.ry @@ -0,0 +1,188 @@ +# vim: syntax=ruby +class Nagios::Parser + +token DEFINE NAME STRING PARAM LCURLY RCURLY VALUE RETURN COMMENT INLINECOMMENT + +rule +decls: decl { return val[0] if val[0] } + | decls decl { + if val[1].nil? + result = val[0] + else + if val[0].nil? + result = val[1] + else + result = [ val[0], val[1] ].flatten + end + end + } + ; + +decl: object { result = [val[0]] } + | RETURN { result = nil } + | comment + ; + +comment: COMMENT RETURN { result = nil } + ; + +object: DEFINE NAME LCURLY RETURN vars RCURLY { + result = Nagios::Base.create(val[1],val[4]) + } + ; + +vars: var + | vars var { + val[1].each {|p,v| + val[0][p] = v + } + result = val[0] + } + ; + +var: PARAM VALUE icomment returns { result = {val[0],val[1]} } + ; + +returns: RETURN + | returns RETURN + ; + +icomment: # nothing + | INLINECOMMENT + ; + +end + +----inner + +def parse(src) + @src = src + + # state variables + @invar = false + @inobject = false + @done = false + + @line = 0 + @yydebug = true + + begin + do_parse + rescue SyntaxError + $stderr.print "#{$!}\n" + exit + end +end + +# The lexer. Very simple. +def token + @src.sub!(/\A\n/,'') + if $& + @line += 1 + return [ :RETURN, "\n" ] + end + + if @done + return nil + end + yytext = String.new + + + # remove comments from this line + @src.sub!(/\A[ \t]*;.*\n/,"\n") + if $& + return [:INLINECOMMENT, ""] + end + + @src.sub!(/\A#.*\n/,"\n") + if $& + return [:COMMENT, ""] + end + + @src.sub!(/#.*/,'') + + if @src.length == 0 + @done = true + return [false, '$'] + end + + if @invar + @src.sub!(/\A[ \t]+/,'') + @src.sub!(/\A([^;\n]+)(\n|;)/,'\2') + if $1 + yytext += $1 + end + @invar = false + return [:VALUE, yytext] + else + @src.sub!(/\A[\t ]*(\S+)([\t ]*|$)/,'') + if $1 + yytext = $1 + case yytext + when 'define' + #puts "got define" + return [:DEFINE, yytext] + when '{' + #puts "got {" + @inobject = true + return [:LCURLY, yytext] + else + unless @inobject + #puts "got type: #{yytext}" + if yytext =~ /\W/ + giveback = yytext.dup + giveback.sub!(/^\w+/,'') + #puts "giveback " + giveback + #puts "yytext " + yytext + yytext.sub!(/\W.*$/,'') + #puts "yytext " + yytext + #puts "all [#{giveback} #{yytext} #{orig}]" + @src = giveback + @src + end + return [:NAME, yytext] + else + if yytext == '}' + #puts "got closure: #{yytext}" + @inobject = false + return [:RCURLY, '}'] + end + + unless @invar + @invar = true + return [:PARAM, $1] + else + end + end + end + end + end +end + +def next_token + token +end + +def yydebug + 1 +end + +def yywrap + 0 +end + +def on_error(token, value, vstack ) + msg = "" + unless value.nil? + msg = "line #{@line}: syntax error at '#{value}'" + else + msg = "line #{@line}: syntax error at '#{token}'" + end + unless @src.size > 0 + msg = "line #{@line}: Unexpected end of file" + end + if token == '$end'.intern + puts "okay, this is silly" + else + raise SyntaxError, msg + end +end diff --git a/lib/puppet/external/nagios/makefile b/lib/puppet/external/nagios/makefile new file mode 100644 index 000000000..fc14564b7 --- /dev/null +++ b/lib/puppet/external/nagios/makefile @@ -0,0 +1,9 @@ +all: parser.rb + +debug: parser.rb setdebug + +parser.rb: grammar.ry + racc -E -oparser.rb grammar.ry + +setdebug: + perl -pi -e 's{\@yydebug =.*$$}{\@yydebug = true}' parser.rb diff --git a/lib/puppet/external/nagios/parser.rb b/lib/puppet/external/nagios/parser.rb new file mode 100644 index 000000000..b7e2c21d8 --- /dev/null +++ b/lib/puppet/external/nagios/parser.rb @@ -0,0 +1,816 @@ +# +# DO NOT MODIFY!!!! +# This file is automatically generated by racc 1.4.4 +# from racc grammer file "grammar.ry". +# +# +# parser.rb: generated by racc (runtime embedded) +# + +###### racc/parser.rb + +unless $".index 'racc/parser.rb' +$".push 'racc/parser.rb' + +self.class.module_eval <<'..end /usr/lib/ruby/1.8/racc/parser.rb modeval..id1306b79176', '/usr/lib/ruby/1.8/racc/parser.rb', 1 +# +# parser.rb +# +# Copyright (c) 1999-2003 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the same terms of ruby. +# +# As a special exception, when this code is copied by Racc +# into a Racc output file, you may use that output file +# without restriction. +# +# $raccId: parser.rb,v 1.4 2003/11/03 13:41:47 aamine Exp $ +# + +unless defined?(NotImplementedError) + NotImplementedError = NotImplementError +end + +module Racc + class ParseError < StandardError; end +end +unless defined?(::ParseError) + ParseError = Racc::ParseError +end + + +module Racc + + unless defined?(Racc_No_Extentions) + Racc_No_Extentions = false + end + + class Parser + + Racc_Runtime_Version = '1.4.4' + Racc_Runtime_Revision = '$raccRevision: 1.4 $'.split[1] + + Racc_Runtime_Core_Version_R = '1.4.4' + Racc_Runtime_Core_Revision_R = '$raccRevision: 1.4 $'.split[1] + begin + require 'racc/cparse' + # Racc_Runtime_Core_Version_C = (defined in extension) + Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2] + unless new.respond_to?(:_racc_do_parse_c, true) + raise LoadError, 'old cparse.so' + end + if Racc_No_Extentions + raise LoadError, 'selecting ruby version of racc runtime core' + end + + Racc_Main_Parsing_Routine = :_racc_do_parse_c + Racc_YY_Parse_Method = :_racc_yyparse_c + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C + Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C + Racc_Runtime_Type = 'c' + rescue LoadError + Racc_Main_Parsing_Routine = :_racc_do_parse_rb + Racc_YY_Parse_Method = :_racc_yyparse_rb + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R + Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R + Racc_Runtime_Type = 'ruby' + end + + def Parser.racc_runtime_type + Racc_Runtime_Type + end + + private + + def _racc_setup + @yydebug = false unless self.class::Racc_debug_parser + @yydebug = false unless defined?(@yydebug) + if @yydebug + @racc_debug_out = $stderr unless defined?(@racc_debug_out) + @racc_debug_out ||= $stderr + end + arg = self.class::Racc_arg + arg[13] = true if arg.size < 14 + arg + end + + def _racc_init_sysvars + @racc_state = [0] + @racc_tstack = [] + @racc_vstack = [] + + @racc_t = nil + @racc_val = nil + + @racc_read_next = true + + @racc_user_yyerror = false + @racc_error_status = 0 + end + + ### + ### do_parse + ### + + def do_parse + __send__(Racc_Main_Parsing_Routine, _racc_setup(), false) + end + + def next_token + raise NotImplementedError, "#{self.class}\#next_token is not defined" + end + + def _racc_do_parse_rb( arg, in_debug ) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + + _racc_init_sysvars + tok = act = i = nil + nerr = 0 + + catch(:racc_end_parse) { + while true + if i = action_pointer[@racc_state[-1]] + if @racc_read_next + if @racc_t != 0 # not EOF + tok, @racc_val = next_token() + unless tok # EOF + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + racc_read_token(@racc_t, tok, @racc_val) if @yydebug + @racc_read_next = false + end + end + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + else + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + } + end + + ### + ### yyparse + ### + + def yyparse( recv, mid ) + __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup(), true) + end + + def _racc_yyparse_rb( recv, mid, arg, c_debug ) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + + _racc_init_sysvars + tok = nil + act = nil + i = nil + nerr = 0 + + catch(:racc_end_parse) { + until i = action_pointer[@racc_state[-1]] + while act = _racc_evalact(action_default[@racc_state[-1]], arg) + ; + end + end + recv.__send__(mid) do |tok, val| +# $stderr.puts "rd: tok=#{tok}, val=#{val}" + unless tok + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + @racc_val = val + @racc_read_next = false + + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] +# $stderr.puts "02: act=#{act}" +# $stderr.puts "curstate=#{@racc_state[-1]}" + else +# $stderr.puts "01: act=#{act}" + end + + while act = _racc_evalact(act, arg) + ; + end + + while not (i = action_pointer[@racc_state[-1]]) or + not @racc_read_next or + @racc_t == 0 # $ + unless i and i += @racc_t and + i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] +# $stderr.puts "04: act=#{act}" + else +# $stderr.puts "03: act=#{act}" + end + while act = _racc_evalact(act, arg) + ; + end + end + end + } + end + + ### + ### common + ### + + def _racc_evalact( act, arg ) +# $stderr.puts "ea: act=#{act}" + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg +nerr = 0 # tmp + + if act > 0 and act < shift_n + # + # shift + # + if @racc_error_status > 0 + @racc_error_status -= 1 unless @racc_t == 1 # error token + end + @racc_vstack.push @racc_val + @racc_state.push act + @racc_read_next = true + if @yydebug + @racc_tstack.push @racc_t + racc_shift @racc_t, @racc_tstack, @racc_vstack + end + + elsif act < 0 and act > -reduce_n + # + # reduce + # + code = catch(:racc_jump) { + @racc_state.push _racc_do_reduce(arg, act) + false + } + if code + case code + when 1 # yyerror + @racc_user_yyerror = true # user_yyerror + return -reduce_n + when 2 # yyaccept + return shift_n + else + raise RuntimeError, '[Racc Bug] unknown jump code' + end + end + + elsif act == shift_n + # + # accept + # + racc_accept if @yydebug + throw :racc_end_parse, @racc_vstack[0] + + elsif act == -reduce_n + # + # error + # + case @racc_error_status + when 0 + unless arg[21] # user_yyerror + nerr += 1 + on_error @racc_t, @racc_val, @racc_vstack + end + when 3 + if @racc_t == 0 # is $ + throw :racc_end_parse, nil + end + @racc_read_next = true + end + @racc_user_yyerror = false + @racc_error_status = 3 + while true + if i = action_pointer[@racc_state[-1]] + i += 1 # error token + if i >= 0 and + (act = action_table[i]) and + action_check[i] == @racc_state[-1] + break + end + end + + throw :racc_end_parse, nil if @racc_state.size <= 1 + @racc_state.pop + @racc_vstack.pop + if @yydebug + @racc_tstack.pop + racc_e_pop @racc_state, @racc_tstack, @racc_vstack + end + end + return act + + else + raise RuntimeError, "[Racc Bug] unknown action #{act.inspect}" + end + + racc_next_state(@racc_state[-1], @racc_state) if @yydebug + + nil + end + + def _racc_do_reduce( arg, act ) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + state = @racc_state + vstack = @racc_vstack + tstack = @racc_tstack + + i = act * -3 + len = reduce_table[i] + reduce_to = reduce_table[i+1] + method_id = reduce_table[i+2] + void_array = [] + + tmp_t = tstack[-len, len] if @yydebug + tmp_v = vstack[-len, len] + tstack[-len, len] = void_array if @yydebug + vstack[-len, len] = void_array + state[-len, len] = void_array + + # tstack must be updated AFTER method call + if use_result + vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) + else + vstack.push __send__(method_id, tmp_v, vstack) + end + tstack.push reduce_to + + racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug + + k1 = reduce_to - nt_base + if i = goto_pointer[k1] + i += state[-1] + if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 + return curstate + end + end + goto_default[k1] + end + + def on_error( t, val, vstack ) + raise ParseError, sprintf("\nparse error on value %s (%s)", + val.inspect, token_to_str(t) || '?') + end + + def yyerror + throw :racc_jump, 1 + end + + def yyaccept + throw :racc_jump, 2 + end + + def yyerrok + @racc_error_status = 0 + end + + # + # for debugging output + # + + def racc_read_token( t, tok, val ) + @racc_debug_out.print 'read ' + @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' + @racc_debug_out.puts val.inspect + @racc_debug_out.puts + end + + def racc_shift( tok, tstack, vstack ) + @racc_debug_out.puts "shift #{racc_token2str tok}" + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_reduce( toks, sim, tstack, vstack ) + out = @racc_debug_out + out.print 'reduce ' + if toks.empty? + out.print ' ' + else + toks.each {|t| out.print ' ', racc_token2str(t) } + end + out.puts " --> #{racc_token2str(sim)}" + + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_accept + @racc_debug_out.puts 'accept' + @racc_debug_out.puts + end + + def racc_e_pop( state, tstack, vstack ) + @racc_debug_out.puts 'error recovering mode: pop token' + racc_print_states state + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_next_state( curstate, state ) + @racc_debug_out.puts "goto #{curstate}" + racc_print_states state + @racc_debug_out.puts + end + + def racc_print_stacks( t, v ) + out = @racc_debug_out + out.print ' [' + t.each_index do |i| + out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' + end + out.puts ' ]' + end + + def racc_print_states( s ) + out = @racc_debug_out + out.print ' [' + s.each {|st| out.print ' ', st } + out.puts ' ]' + end + + def racc_token2str( tok ) + self.class::Racc_token_to_s_table[tok] or + raise RuntimeError, "[Racc Bug] can't convert token #{tok} to string" + end + + def token_to_str( t ) + self.class::Racc_token_to_s_table[t] + end + + end + +end +..end /usr/lib/ruby/1.8/racc/parser.rb modeval..id1306b79176 +end # end of racc/parser.rb + + +module Nagios + + class Parser < Racc::Parser + +module_eval <<'..end grammar.ry modeval..id458299781d', 'grammar.ry', 57 + +def parse(src) + @src = src + + # state variables + @invar = false + @inobject = false + @done = false + + @line = 0 + @yydebug = true + + begin + do_parse + rescue SyntaxError + $stderr.print "#{$!}\n" + exit + end +end + +# The lexer. Very simple. +def token + @src.sub!(/\A\n/,'') + if $& + @line += 1 + return [ :RETURN, "\n" ] + end + + if @done + return nil + end + yytext = String.new + + + # remove comments from this line + @src.sub!(/\A[ \t]*;.*\n/,"\n") + if $& + return [:INLINECOMMENT, ""] + end + + @src.sub!(/\A#.*\n/,"\n") + if $& + return [:COMMENT, ""] + end + + @src.sub!(/#.*/,'') + + if @src.length == 0 + @done = true + return [false, '$'] + end + + if @invar + @src.sub!(/\A[ \t]+/,'') + @src.sub!(/\A([^;\n]+)(\n|;)/,'\2') + if $1 + yytext += $1 + end + @invar = false + return [:VALUE, yytext] + else + @src.sub!(/\A[\t ]*(\S+)([\t ]*|$)/,'') + if $1 + yytext = $1 + case yytext + when 'define' + #puts "got define" + return [:DEFINE, yytext] + when '{' + #puts "got {" + @inobject = true + return [:LCURLY, yytext] + else + unless @inobject + #puts "got type: #{yytext}" + if yytext =~ /\W/ + giveback = yytext.dup + giveback.sub!(/^\w+/,'') + #puts "giveback " + giveback + #puts "yytext " + yytext + yytext.sub!(/\W.*$/,'') + #puts "yytext " + yytext + #puts "all [#{giveback} #{yytext} #{orig}]" + @src = giveback + @src + end + return [:NAME, yytext] + else + if yytext == '}' + #puts "got closure: #{yytext}" + @inobject = false + return [:RCURLY, '}'] + end + + unless @invar + @invar = true + return [:PARAM, $1] + else + end + end + end + end + end +end + +def next_token + token +end + +def yydebug + 1 +end + +def yywrap + 0 +end + +def on_error(token, value, vstack ) + msg = "" + unless value.nil? + msg = "line #{@line}: syntax error at '#{value}'" + else + msg = "line #{@line}: syntax error at '#{token}'" + end + unless @src.size > 0 + msg = "line #{@line}: Unexpected end of file" + end + if token == '$end'.intern + puts "okay, this is silly" + else + raise SyntaxError, msg + end +end +..end grammar.ry modeval..id458299781d + +##### racc 1.4.4 generates ### + +racc_reduce_table = [ + 0, 0, :racc_error, + 1, 13, :_reduce_1, + 2, 13, :_reduce_2, + 1, 14, :_reduce_3, + 1, 14, :_reduce_4, + 1, 14, :_reduce_none, + 2, 16, :_reduce_6, + 6, 15, :_reduce_7, + 1, 17, :_reduce_none, + 2, 17, :_reduce_9, + 4, 18, :_reduce_10, + 1, 20, :_reduce_none, + 2, 20, :_reduce_none, + 0, 19, :_reduce_none, + 1, 19, :_reduce_none ] + +racc_reduce_n = 15 + +racc_shift_n = 26 + +racc_action_table = [ + 9, 15, 1, 20, 1, 14, 12, 13, 11, 6, + 7, 6, 7, 15, 18, 8, 21, 23, 25 ] + +racc_action_check = [ + 2, 16, 2, 16, 0, 12, 8, 9, 7, 2, + 2, 0, 0, 14, 15, 1, 18, 22, 24 ] + +racc_action_pointer = [ + 2, 12, 0, nil, nil, nil, nil, -1, 0, 7, + nil, nil, -4, nil, 8, 6, -4, nil, 5, nil, + nil, nil, 8, nil, 9, nil ] + +racc_action_default = [ + -15, -15, -15, -1, -3, -5, -4, -15, -15, -15, + -2, -6, -15, 26, -15, -15, -15, -8, -13, -9, + -7, -14, -15, -11, -10, -12 ] + +racc_goto_table = [ + 17, 3, 19, 10, 2, 16, 22, 24 ] + +racc_goto_check = [ + 6, 2, 6, 2, 1, 5, 7, 8 ] + +racc_goto_pointer = [ + nil, 4, 1, nil, nil, -9, -14, -12, -15 ] + +racc_goto_default = [ + nil, nil, nil, 4, 5, nil, nil, nil, nil ] + +racc_token_table = { + false => 0, + Object.new => 1, + :DEFINE => 2, + :NAME => 3, + :STRING => 4, + :PARAM => 5, + :LCURLY => 6, + :RCURLY => 7, + :VALUE => 8, + :RETURN => 9, + :COMMENT => 10, + :INLINECOMMENT => 11 } + +racc_use_result_var = true + +racc_nt_base = 12 + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ +'$end', +'error', +'DEFINE', +'NAME', +'STRING', +'PARAM', +'LCURLY', +'RCURLY', +'VALUE', +'RETURN', +'COMMENT', +'INLINECOMMENT', +'$start', +'decls', +'decl', +'object', +'comment', +'vars', +'var', +'icomment', +'returns'] + +Racc_debug_parser = false + +##### racc system variables end ##### + + # reduce 0 omitted + +module_eval <<'.,.,', 'grammar.ry', 6 + def _reduce_1( val, _values, result ) + return val[0] if val[0] + result + end +.,., + +module_eval <<'.,.,', 'grammar.ry', 18 + def _reduce_2( val, _values, result ) + if val[1].nil? + result = val[0] + else + if val[0].nil? + result = val[1] + else + result = [ val[0], val[1] ].flatten + end + end + result + end +.,., + +module_eval <<'.,.,', 'grammar.ry', 20 + def _reduce_3( val, _values, result ) + result = [val[0]] + result + end +.,., + +module_eval <<'.,.,', 'grammar.ry', 21 + def _reduce_4( val, _values, result ) + result = nil + result + end +.,., + + # reduce 5 omitted + +module_eval <<'.,.,', 'grammar.ry', 25 + def _reduce_6( val, _values, result ) + result = nil + result + end +.,., + +module_eval <<'.,.,', 'grammar.ry', 31 + def _reduce_7( val, _values, result ) + result = Nagios::Base.create(val[1],val[4]) + result + end +.,., + + # reduce 8 omitted + +module_eval <<'.,.,', 'grammar.ry', 40 + def _reduce_9( val, _values, result ) + val[1].each {|p,v| + val[0][p] = v + } + result = val[0] + result + end +.,., + +module_eval <<'.,.,', 'grammar.ry', 42 + def _reduce_10( val, _values, result ) + result = {val[0],val[1]} + result + end +.,., + + # reduce 11 omitted + + # reduce 12 omitted + + # reduce 13 omitted + + # reduce 14 omitted + + def _reduce_none( val, _values, result ) + result + end + + end # class Parser + +end # module Nagios diff --git a/lib/puppet/provider/naginator.rb b/lib/puppet/provider/naginator.rb new file mode 100644 index 000000000..8e8a3d65e --- /dev/null +++ b/lib/puppet/provider/naginator.rb @@ -0,0 +1,55 @@ +# Created by Luke Kanies on 2007-11-27. +# Copyright (c) 2007. All rights reserved. + +require 'puppet' +require 'puppet/provider/parsedfile' +require 'puppet/external/nagios' + +# The base class for all Naginator providers. +class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile + # Retrieve the associated class from Nagios::Base. + def self.nagios_type + unless defined?(@nagios_type) and @nagios_type + name = resource_type.name.to_s.sub(/^nagios_/, '') + unless @nagios_type = Nagios::Base.type(name.to_sym) + raise Puppet::DevError, "Could not find nagios type '%s'" % name + end + + # And add our 'ensure' settings, since they aren't a part of + # Naginator by default + @nagios_type.send(:attr_accessor, :ensure, :target, :on_disk) + end + @nagios_type + end + + def self.parse(text) + Nagios::Parser.new.parse(text) + end + + def self.to_file(records) + header + records.collect { |record| record.to_s }.join("\n") + end + + def self.skip_record?(record) + false + end + + def self.valid_attr?(klass, attr_name) + nagios_type.parameters.include?(attr_name) + end + + def initialize(resource = nil) + if resource.is_a?(Nagios::Base) + # We don't use a duplicate here, because some providers (ParsedFile, at least) + # use the hash here for later events. + @property_hash = resource + elsif resource + @resource = resource if resource + # LAK 2007-05-09: Keep the model stuff around for backward compatibility + @model = resource + @property_hash = self.class.nagios_type.new + else + @property_hash = self.class.nagios_type.new + end + end +end diff --git a/lib/puppet/provider/parsedfile.rb b/lib/puppet/provider/parsedfile.rb index 76654c4f4..b4a4a3b91 100755 --- a/lib/puppet/provider/parsedfile.rb +++ b/lib/puppet/provider/parsedfile.rb @@ -1,364 +1,370 @@ require 'puppet' require 'puppet/util/filetype' require 'puppet/util/fileparsing' # This provider can be used as the parent class for a provider that # parses and generates files. Its content must be loaded via the # 'prefetch' method, and the file will be written when 'flush' is called # on the provider instance. At this point, the file is written once # for every provider instance. # # Once the provider prefetches the data, it's the resource's job to copy # that data over to the @is variables. class Puppet::Provider::ParsedFile < Puppet::Provider extend Puppet::Util::FileParsing class << self attr_accessor :default_target, :target end attr_accessor :property_hash def self.clean(hash) newhash = hash.dup [:record_type, :on_disk].each do |p| if newhash.include?(p) newhash.delete(p) end end return newhash end def self.clear @target_objects.clear @records.clear end def self.filetype unless defined? @filetype @filetype = Puppet::Util::FileType.filetype(:flat) end return @filetype end def self.filetype=(type) if type.is_a?(Class) @filetype = type elsif klass = Puppet::Util::FileType.filetype(type) @filetype = klass else raise ArgumentError, "Invalid filetype %s" % type end end # Flush all of the targets for which there are modified records. The only # reason we pass a record here is so that we can add it to the stack if # necessary -- it's passed from the instance calling 'flush'. def self.flush(record) # Make sure this record is on the list to be flushed. unless record[:on_disk] record[:on_disk] = true @records << record # If we've just added the record, then make sure our # target will get flushed. modified(record[:target] || default_target) end return unless defined?(@modified) and ! @modified.empty? flushed = [] @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target| Puppet.debug "Flushing %s provider target %s" % [@resource_type.name, target] flush_target(target) flushed << target end @modified.reject! { |t| flushed.include?(t) } end # Flush all of the records relating to a specific target. def self.flush_target(target) records = target_records(target).reject { |r| r[:ensure] == :absent } target_object(target).write(to_file(records)) end # Return the header placed at the top of each generated file, warning # users that modifying this file manually is probably a bad idea. def self.header %{# HEADER: This file was autogenerated at #{Time.now} # HEADER: by puppet. While it can still be managed manually, it # HEADER: is definitely not recommended.\n} end # Add another type var. def self.initvars @records = [] @target_objects = {} @target = nil # Default to flat files @filetype ||= Puppet::Util::FileType.filetype(:flat) super end # Return a list of all of the records we can find. def self.instances prefetch() @records.find_all { |r| r[:record_type] == self.name }.collect { |r| new(r) } end # Override the default method with a lot more functionality. def self.mk_resource_methods [resource_type.validproperties, resource_type.parameters].flatten.each do |attr| attr = symbolize(attr) define_method(attr) do # if @property_hash.empty? # # Note that this swaps the provider out from under us. # prefetch() # if @resource.provider == self # return @property_hash[attr] # else # return @resource.provider.send(attr) # end # end # If it's not a valid field for this record type (which can happen # when different platforms support different fields), then just # return the should value, so the resource shuts up. if @property_hash[attr] or self.class.valid_attr?(self.class.name, attr) @property_hash[attr] || :absent else if defined? @resource @resource.should(attr) else nil end end end define_method(attr.to_s + "=") do |val| mark_target_modified @property_hash[attr] = val end end end # Always make the resource methods. def self.resource_type=(resource) super mk_resource_methods() end # Mark a target as modified so we know to flush it. This only gets # used within the attr= methods. def self.modified(target) @modified ||= [] @modified << target unless @modified.include?(target) end # Retrieve all of the data from disk. There are three ways to know # which files to retrieve: We might have a list of file objects already # set up, there might be instances of our associated resource and they # will have a path parameter set, and we will have a default path # set. We need to turn those three locations into a list of files, # prefetch each one, and make sure they're associated with each appropriate # resource instance. def self.prefetch(resources = nil) # Reset the record list. @records = [] targets(resources).each do |target| @records += prefetch_target(target) end if resources matchers = resources.dup @records.each do |record| # Skip things like comments and blank lines - next if record_type(record[:record_type]).text? + next if skip_record?(record) if name = record[:name] and resource = resources[name] resource.provider = new(record) elsif respond_to?(:match) if resource = match(record, matchers) # Remove this resource from circulation so we don't unnecessarily try to match matchers.delete(resource.title) record[:name] = resource[:name] resource.provider = new(record) end end end end end # Prefetch an individual target. def self.prefetch_target(target) target_records = retrieve(target).each do |r| r[:on_disk] = true r[:target] = target r[:ensure] = :present end if respond_to?(:prefetch_hook) target_records = prefetch_hook(target_records) end unless target_records raise Puppet::DevError, "Prefetching %s for provider %s returned nil" % [target, self.name] end target_records end # Is there an existing record with this name? def self.record?(name) @records.find { |r| r[:name] == name } end # Retrieve the text for the file. Returns nil in the unlikely # event that it doesn't exist. def self.retrieve(path) # XXX We need to be doing something special here in case of failure. text = target_object(path).read if text.nil? or text == "" # there is no file return [] else # Set the target, for logging. old = @target begin @target = path return self.parse(text) rescue Puppet::Error => detail detail.file = @target raise detail ensure @target = old end end end + # Should we skip the record? Basically, we skip text records. + # This is only here so subclasses can override it. + def self.skip_record?(record) + record_type(record[:record_type]).text? + end + # Initialize the object if necessary. def self.target_object(target) @target_objects[target] ||= filetype.new(target) @target_objects[target] end # Find all of the records for a given target def self.target_records(target) @records.find_all { |r| r[:target] == target } end # Find a list of all of the targets that we should be reading. This is # used to figure out what targets we need to prefetch. def self.targets(resources = nil) targets = [] # First get the default target unless self.default_target raise Puppet::DevError, "Parsed Providers must define a default target" end targets << self.default_target # Then get each of the file objects targets += @target_objects.keys # Lastly, check the file from any resource instances if resources resources.each do |name, resource| if value = resource.should(:target) targets << value end end end targets.uniq.compact end def self.to_file(records) text = super header + text end def create @resource.class.validproperties.each do |property| if value = @resource.should(property) @property_hash[property] = value end end mark_target_modified() return (@resource.class.name.to_s + "_created").intern end def destroy # We use the method here so it marks the target as modified. self.ensure = :absent return (@resource.class.name.to_s + "_deleted").intern end def exists? if @property_hash[:ensure] == :absent or @property_hash[:ensure].nil? return false else return true end end # Write our data to disk. def flush # Make sure we've got a target and name set. # If the target isn't set, then this is our first modification, so # mark it for flushing. unless @property_hash[:target] @property_hash[:target] = @resource.should(:target) || self.class.default_target self.class.modified(@property_hash[:target]) end @property_hash[:name] ||= @resource.name self.class.flush(@property_hash) #@property_hash = {} end def initialize(record) super # The 'record' could be a resource or a record, depending on how the provider # is initialized. If we got an empty property hash (probably because the resource # is just being initialized), then we want to set up some defualts. if @property_hash.empty? @property_hash = self.class.record?(resource[:name]) || {:record_type => self.class.name, :ensure => :absent} end end # Retrieve the current state from disk. def prefetch unless @resource raise Puppet::DevError, "Somehow got told to prefetch with no resource set" end self.class.prefetch(@resource[:name] => @resource) end def record_type @property_hash[:record_type] end private # Mark both the resource and provider target as modified. def mark_target_modified if defined? @resource and restarget = @resource.should(:target) and restarget != @property_hash[:target] self.class.modified(restarget) end if @property_hash[:target] != :absent and @property_hash[:target] self.class.modified(@property_hash[:target]) end end end diff --git a/lib/puppet/type/nagios_command.rb b/lib/puppet/type/nagios_command.rb new file mode 100644 index 000000000..0d0e11b17 --- /dev/null +++ b/lib/puppet/type/nagios_command.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :command diff --git a/lib/puppet/type/nagios_contact.rb b/lib/puppet/type/nagios_contact.rb new file mode 100644 index 000000000..d5a1f3cba --- /dev/null +++ b/lib/puppet/type/nagios_contact.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :contact diff --git a/lib/puppet/type/nagios_contactgroup.rb b/lib/puppet/type/nagios_contactgroup.rb new file mode 100644 index 000000000..b8f14c07b --- /dev/null +++ b/lib/puppet/type/nagios_contactgroup.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :contactgroup diff --git a/lib/puppet/type/nagios_host.rb b/lib/puppet/type/nagios_host.rb new file mode 100644 index 000000000..f2e03f6fb --- /dev/null +++ b/lib/puppet/type/nagios_host.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :host diff --git a/lib/puppet/type/nagios_hostextinfo.rb b/lib/puppet/type/nagios_hostextinfo.rb new file mode 100644 index 000000000..da8e08dd8 --- /dev/null +++ b/lib/puppet/type/nagios_hostextinfo.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :hostextinfo diff --git a/lib/puppet/type/nagios_hostgroup.rb b/lib/puppet/type/nagios_hostgroup.rb new file mode 100644 index 000000000..e1943beec --- /dev/null +++ b/lib/puppet/type/nagios_hostgroup.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :hostgroup diff --git a/lib/puppet/type/nagios_hostgroupescalation.rb b/lib/puppet/type/nagios_hostgroupescalation.rb new file mode 100644 index 000000000..21b39f681 --- /dev/null +++ b/lib/puppet/type/nagios_hostgroupescalation.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :hostgroupescalation diff --git a/lib/puppet/type/nagios_service.rb b/lib/puppet/type/nagios_service.rb new file mode 100644 index 000000000..22b987f56 --- /dev/null +++ b/lib/puppet/type/nagios_service.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :service diff --git a/lib/puppet/type/nagios_servicedependency.rb b/lib/puppet/type/nagios_servicedependency.rb new file mode 100644 index 000000000..0e3340c6e --- /dev/null +++ b/lib/puppet/type/nagios_servicedependency.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :servicedependency diff --git a/lib/puppet/type/nagios_serviceescalation.rb b/lib/puppet/type/nagios_serviceescalation.rb new file mode 100644 index 000000000..cb2af1545 --- /dev/null +++ b/lib/puppet/type/nagios_serviceescalation.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :serviceescalation diff --git a/lib/puppet/type/nagios_serviceextinfo.rb b/lib/puppet/type/nagios_serviceextinfo.rb new file mode 100644 index 000000000..6bdc70900 --- /dev/null +++ b/lib/puppet/type/nagios_serviceextinfo.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :serviceextinfo diff --git a/lib/puppet/type/nagios_timeperiod.rb b/lib/puppet/type/nagios_timeperiod.rb new file mode 100644 index 000000000..25a06d3ed --- /dev/null +++ b/lib/puppet/type/nagios_timeperiod.rb @@ -0,0 +1,3 @@ +require 'puppet/util/nagios_maker' + +Puppet::Util::NagiosMaker.create_nagios_type :timeperiod diff --git a/lib/puppet/util/nagios_maker.rb b/lib/puppet/util/nagios_maker.rb new file mode 100644 index 000000000..f1f85466f --- /dev/null +++ b/lib/puppet/util/nagios_maker.rb @@ -0,0 +1,56 @@ +require 'puppet/external/nagios' +require 'puppet/external/nagios/base' +require 'puppet/provider/naginator' + +module Puppet::Util::NagiosMaker + # Create a new nagios type, using all of the parameters + # from the parser. + def self.create_nagios_type(name) + name = name.to_sym + full_name = ("nagios_" + name.to_s).to_sym + + raise(Puppet::DevError, "No nagios type for %s" % name) unless nagtype = Nagios::Base.type(name) + + type = Puppet::Type.newtype(full_name) {} + + type.ensurable + + type.newparam(nagtype.namevar, :namevar => true) do + desc "The name parameter for Nagios type %s" % nagtype.name + end + + # We deduplicate the parameters because it makes sense to allow Naginator to have dupes. + nagtype.parameters.uniq.each do |param| + next if param == nagtype.namevar + + # We can't turn these parameter names into constants, so at least for now they aren't + # supported. + next if param.to_s =~ /^[0-9]/ + + type.newproperty(param) do + desc "Nagios configuration file parameter." + end + end + + type.newproperty(:target) do + desc 'target' + + defaultto do + resource.class.defaultprovider.default_target + end + end + + provider = type.provide(:naginator, :parent => Puppet::Provider::Naginator, :default_target => "/etc/nagios/#{full_name.to_s}.cfg") {} + + type.desc "The Nagios type #{name.to_s}. This resource type is autogenerated using the + model developed in Naginator_, and all of the Nagios types are generated using the + same code and the same library. + + This type generates Nagios configuration statements in Nagios-parseable configuration + files. By default, the statements will be added to ``#{provider.default_target}, but + you can send them to a different file by setting their ``target`` attribute. + + .. _naginator: http://reductivelabs.com/trac/naginator + " + end +end diff --git a/spec/unit/ral/types/nagios.rb b/spec/unit/ral/types/nagios.rb new file mode 100755 index 000000000..8aca7d401 --- /dev/null +++ b/spec/unit/ral/types/nagios.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/external/nagios' + +Nagios::Base.eachtype do |name, nagios_type| + puppet_type = Puppet::Type.type("nagios_" + name.to_s) + + describe puppet_type do + it "should be defined as a Puppet resource type" do + puppet_type.should_not be_nil + end + + it "should have documentation" do + puppet_type.instance_variable_get("@doc").should_not == "" + end + + it "should have %s as its namevar" % nagios_type.namevar do + puppet_type.namevar.should == nagios_type.namevar + end + + it "should have documentation for its %s parameter" % nagios_type.namevar do + puppet_type.attrclass(nagios_type.namevar).instance_variable_get("@doc").should_not be_nil + end + + it "should have an ensure property" do + puppet_type.should be_validproperty(:ensure) + end + + it "should have a target property" do + puppet_type.should be_validproperty(:target) + end + + it "should have documentation for its target property" do + puppet_type.attrclass(:target).instance_variable_get("@doc").should_not be_nil + end + + nagios_type.parameters.reject { |param| param == nagios_type.namevar or param.to_s =~ /^[0-9]/ }.each do |param| + it "should have a %s property" % param do + puppet_type.should be_validproperty(param) + end + + it "should have documentation for its %s property" % param do + puppet_type.attrclass(param).instance_variable_get("@doc").should_not be_nil + end + end + + nagios_type.parameters.find_all { |param| param.to_s =~ /^[0-9]/ }.each do |param| + it "should have not have a %s property" % param do + puppet_type.should_not be_validproperty(:param) + end + end + end +end diff --git a/spec/unit/util/nagios_maker.rb b/spec/unit/util/nagios_maker.rb new file mode 100755 index 000000000..0454b6503 --- /dev/null +++ b/spec/unit/util/nagios_maker.rb @@ -0,0 +1,128 @@ +#!/usr/bin/env ruby +# +# Created by Luke Kanies on 2007-11-18. +# Copyright (c) 2007. All rights reserved. + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/util/nagios_maker' + +describe Puppet::Util::NagiosMaker do + before do + @module = Puppet::Util::NagiosMaker + + @nagtype = stub 'nagios type', :parameters => [], :namevar => :name + Nagios::Base.stubs(:type).with(:test).returns(@nagtype) + end + + it "should be able to create a new nagios type" do + @module.should respond_to(:create_nagios_type) + end + + it "should fail if it cannot find the named Naginator type" do + Nagios::Base.stubs(:type).returns(nil) + + lambda { @module.create_nagios_type(:no_such_type) }.should raise_error(Puppet::DevError) + end + + it "should create a new RAL type with the provided name prefixed with 'nagios_'" do + type = stub 'type', :newparam => nil, :newproperty => nil, :ensurable => nil, :provide => nil + + Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + @module.create_nagios_type(:test) + end + + it "should mark the created type as ensurable" do + type = stub 'type', :newparam => nil, :newproperty => nil, :provide => nil + + type.expects(:ensurable) + + Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + @module.create_nagios_type(:test) + end + + it "should create a namevar parameter for the nagios type's name parameter" do + type = stub 'type', :newproperty => nil, :ensurable => nil, :provide => nil + + type.expects(:newparam).with(:name, :namevar => true) + + Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + @module.create_nagios_type(:test) + end + + it "should create a property for all non-namevar parameters" do + type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil + + @nagtype.stubs(:parameters).returns([:one, :two]) + + type.expects(:newproperty).with(:one) + type.expects(:newproperty).with(:two) + type.expects(:newproperty).with(:target) + + Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + @module.create_nagios_type(:test) + end + + it "should skip parameters that start with integers" do + type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil + + @nagtype.stubs(:parameters).returns(["2dcoords".to_sym, :other]) + + type.expects(:newproperty).with(:other) + type.expects(:newproperty).with(:target) + + Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + @module.create_nagios_type(:test) + end + + it "should deduplicate the parameter list" do + type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil + + @nagtype.stubs(:parameters).returns([:one, :one]) + + type.expects(:newproperty).with(:one) + type.expects(:newproperty).with(:target) + + Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + @module.create_nagios_type(:test) + end + + it "should create a target property" do + type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil + + type.expects(:newproperty).with(:target) + + Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + @module.create_nagios_type(:test) + end +end + +describe Puppet::Util::NagiosMaker, " when creating the naginator provider" do + before do + @module = Puppet::Util::NagiosMaker + + @nagtype = stub 'nagios type', :parameters => [], :namevar => :name + Nagios::Base.stubs(:type).with(:test).returns(@nagtype) + + @type = stub 'type', :newparam => nil, :ensurable => nil, :newproperty => nil + Puppet::Type.stubs(:newtype).with(:nagios_test).returns(@type) + end + + it "should add a naginator provider" do + @type.expects(:provide).with { |name, options| name == :naginator } + + @module.create_nagios_type(:test) + end + + it "should set Puppet::Provider::Naginator as the parent class of the provider" do + @type.expects(:provide).with { |name, options| options[:parent] == Puppet::Provider::Naginator } + + @module.create_nagios_type(:test) + end + + it "should use /etc/nagios/$name.cfg as the default target" do + @type.expects(:provide).with { |name, options| options[:default_target] == "/etc/nagios/nagios_test.cfg" } + + @module.create_nagios_type(:test) + end +end