diff options
| author | Dominic Cleal <dcleal@redhat.com> | 2010-11-27 13:36:04 +0000 |
|---|---|---|
| committer | Dominic Cleal <dcleal@redhat.com> | 2010-11-27 13:36:04 +0000 |
| commit | afe2d014feb2210a8666c93465d11e9c9d555f8b (patch) | |
| tree | 208f5ac82b2c29610d2021821c8fca9b079e638b /lib | |
| parent | 143fc744a839affd328234fca26246d49d15d3d8 (diff) | |
| parent | 4b35402ba85d8842d757becec5c8a7bf4d6f6654 (diff) | |
| download | puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.tar.gz puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.tar.xz puppet-afe2d014feb2210a8666c93465d11e9c9d555f8b.zip | |
Merge branch 'master' of github.com:domcleal/puppet into master-old
Diffstat (limited to 'lib')
208 files changed, 4190 insertions, 3931 deletions
diff --git a/lib/puppet.rb b/lib/puppet.rb index 902f5bf5c..78fb5138b 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -24,7 +24,7 @@ require 'puppet/util/run_mode' # it's also a place to find top-level commands like 'debug' module Puppet - PUPPETVERSION = '2.6.0' + PUPPETVERSION = '2.6.3' def Puppet.version PUPPETVERSION diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb index 52acc64aa..47dd44a0e 100644 --- a/lib/puppet/agent.rb +++ b/lib/puppet/agent.rb @@ -37,7 +37,9 @@ class Puppet::Agent with_client do |client| begin sync.synchronize { lock { result = client.run(*args) } } - rescue => detail + rescue SystemExit,NoMemoryError + raise + rescue Exception => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not run #{client_class}: #{detail}" end diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb index 05b7d466f..f0159a65d 100644 --- a/lib/puppet/application.rb +++ b/lib/puppet/application.rb @@ -254,20 +254,6 @@ class Application def preinit end - def option_parser - return @option_parser if defined?(@option_parser) - - @option_parser = OptionParser.new(self.class.banner) - - self.class.option_parser_commands.each do |options, fname| - @option_parser.on(*options) do |value| - self.send(fname, value) - end - end - @option_parser.default_argv = self.command_line.args - @option_parser - end - def initialize(command_line = nil) require 'puppet/util/command_line' @command_line = command_line || Puppet::Util::CommandLine.new @@ -286,7 +272,7 @@ class Application Puppet.settings.set_value(:name, Puppet.application_name.to_s, :mutable_defaults) Puppet.settings.set_value(:logdir, Puppet.run_mode.logopts, :mutable_defaults) Puppet.settings.set_value(:rundir, Puppet.run_mode.run_dir, :mutable_defaults) - Puppet.settings.set_value(:mode, Puppet.run_mode.name.to_s, :mutable_defaults) + Puppet.settings.set_value(:run_mode, Puppet.run_mode.name.to_s, :mutable_defaults) end require 'puppet' @@ -324,20 +310,29 @@ class Application end def parse_options - # get all puppet options - optparse_opt = [] - optparse_opt = Puppet.settings.optparse_addargs(optparse_opt) + # Create an option parser + option_parser = OptionParser.new(self.class.banner) - # convert them to OptionParser format - optparse_opt.each do |option| - self.option_parser.on(*option) do |arg| + # Add all global options to it. + Puppet.settings.optparse_addargs([]).each do |option| + option_parser.on(*option) do |arg| handlearg(option[0], arg) end end - # scan command line argument + # Add options that are local to this application, which were + # created using the "option()" metaprogramming method. If there + # are any conflicts, this application's options will be favored. + self.class.option_parser_commands.each do |options, fname| + option_parser.on(*options) do |value| + # Call the method that "option()" created. + self.send(fname, value) + end + end + + # scan command line. begin - self.option_parser.parse! + option_parser.parse!(self.command_line.args) rescue OptionParser::ParseError => detail $stderr.puts detail $stderr.puts "Try 'puppet #{command_line.subcommand_name} --help'" diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb index f0e7f4d8f..c5ad72068 100644 --- a/lib/puppet/application/agent.rb +++ b/lib/puppet/application/agent.rb @@ -219,12 +219,18 @@ class Puppet::Application::Agent < Puppet::Application Puppet.settings.use :main, :agent, :ssl + # Always ignoreimport for agent. It really shouldn't even try to import, + # but this is just a temporary band-aid. + Puppet[:ignoreimport] = true + # We need to specify a ca location for all of the SSL-related i # indirected classes to work; in fingerprint mode we just need # access to the local files and we don't need a ca. Puppet::SSL::Host.ca_location = options[:fingerprint] ? :none : :remote Puppet::Transaction::Report.terminus_class = :rest + # we want the last report to be persisted locally + Puppet::Transaction::Report.cache_class = :yaml # Override the default; puppetd needs this, usually. # You can still override this on the command-line with, e.g., :compiler. diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb index bb4186dbd..8ec3fab6b 100644 --- a/lib/puppet/application/apply.rb +++ b/lib/puppet/application/apply.rb @@ -78,7 +78,10 @@ class Puppet::Application::Apply < Puppet::Application if options[:code] or command_line.args.length == 0 Puppet[:code] = options[:code] || STDIN.read else - Puppet[:manifest] = command_line.args.shift + manifest = command_line.args.shift + raise "Could not find file #{manifest}" unless File.exist?(manifest) + Puppet.warning("Only one file can be applied per run. Skipping #{command_line.args.join(', ')}") if command_line.args.size > 0 + Puppet[:manifest] = manifest end # Collect our facts. @@ -120,20 +123,9 @@ class Puppet::Application::Apply < Puppet::Application require 'puppet/configurer' configurer = Puppet::Configurer.new - configurer.execute_prerun_command - - # And apply it - transaction = catalog.apply - - configurer.execute_postrun_command + report = configurer.run(:skip_plugin_download => true, :catalog => catalog) - status = 0 - if not Puppet[:noop] and options[:detailed_exitcodes] - transaction.generate_report - exit(transaction.report.exit_status) - else - exit(0) - end + exit( Puppet[:noop] ? 0 : options[:detailed_exitcodes] ? report.exit_status : 0 ) rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts detail.message @@ -156,6 +148,9 @@ class Puppet::Application::Apply < Puppet::Application exit(1) end + # we want the last report to be persisted locally + Puppet::Transaction::Report.cache_class = :yaml + if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] diff --git a/lib/puppet/application/describe.rb b/lib/puppet/application/describe.rb index 5abe3ea14..e76b347f6 100644 --- a/lib/puppet/application/describe.rb +++ b/lib/puppet/application/describe.rb @@ -130,7 +130,7 @@ class TypeDoc a[0].to_s <=> b[0].to_s }.each { |name, doc| print "\n- **#{name}**" - if type.namevar == name and name != :name + if type.key_attributes.include?(name) and name != :name puts " (*namevar*)" else puts "" diff --git a/lib/puppet/application/doc.rb b/lib/puppet/application/doc.rb index 66aa6c8a1..1f6c63286 100644 --- a/lib/puppet/application/doc.rb +++ b/lib/puppet/application/doc.rb @@ -56,7 +56,7 @@ class Puppet::Application::Doc < Puppet::Application end def run_command - return[:rdoc, :trac, :markdown].include?(options[:mode]) ? send(options[:mode]) : other + return[:rdoc].include?(options[:mode]) ? send(options[:mode]) : other end def rdoc @@ -72,7 +72,7 @@ class Puppet::Application::Doc < Puppet::Application Puppet.settings.setdefaults( "puppetdoc", - + "document_all" => [false, "Document all resources"] ) Puppet.settings[:document_all] = options[:all] || false @@ -92,40 +92,6 @@ class Puppet::Application::Doc < Puppet::Application exit exit_code end - def trac - require 'puppet/util/reference' - options[:references].each do |name| - section = Puppet::Util::Reference.reference(name) or raise "Could not find section #{name}" - section.trac unless options[:mode] == :pdf - end - end - - def markdown - text = "" - with_contents = false - exit_code = 0 - require 'puppet/util/reference' - options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name| - raise "Could not find reference #{name}" unless section = Puppet::Util::Reference.reference(name) - - begin - # Add the per-section text, but with no ToC - text += section.send(options[:format], with_contents) - text += Puppet::Util::Reference.footer - text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 } - Puppet::Util::Reference.markdown(name, text) - text = "" - rescue => detail - puts detail.backtrace - $stderr.puts "Could not generate reference #{name}: #{detail}" - exit_code = 1 - next - end - end - - exit exit_code - end - def other text = "" with_contents = options[:references].length <= 1 diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb index 777a50eaa..fde474907 100644 --- a/lib/puppet/application/master.rb +++ b/lib/puppet/application/master.rb @@ -138,9 +138,6 @@ class Puppet::Application::Master < Puppet::Application Puppet.settings.use :main, :master, :ssl - # A temporary solution, to at least make the master work for now. - Puppet::Node::Facts.terminus_class = :yaml - # Cache our nodes in yaml. Currently not configurable. Puppet::Node.cache_class = :yaml diff --git a/lib/puppet/application/queue.rb b/lib/puppet/application/queue.rb index 6df825dd1..239f6b2ad 100644 --- a/lib/puppet/application/queue.rb +++ b/lib/puppet/application/queue.rb @@ -38,6 +38,7 @@ class Puppet::Application::Queue < Puppet::Application option("--verbose","-v") def main + require 'puppet/indirector/catalog/queue' # provides Puppet::Indirector::Queue.subscribe Puppet.notice "Starting puppetqd #{Puppet.version}" Puppet::Resource::Catalog::Queue.subscribe do |catalog| # Once you have a Puppet::Resource::Catalog instance, calling save on it should suffice diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index 327955b03..1c0639029 100644 --- a/lib/puppet/configurer.rb +++ b/lib/puppet/configurer.rb @@ -77,12 +77,12 @@ class Puppet::Configurer end # Prepare for catalog retrieval. Downloads everything necessary, etc. - def prepare + def prepare(options) dostorage - download_plugins + download_plugins unless options[:skip_plugin_download] - download_fact_plugins + download_fact_plugins unless options[:skip_plugin_download] execute_prerun_command end @@ -126,7 +126,7 @@ class Puppet::Configurer # which accepts :tags and :ignoreschedules. def run(options = {}) begin - prepare + prepare(options) rescue SystemExit,NoMemoryError raise rescue Exception => detail @@ -158,25 +158,40 @@ class Puppet::Configurer return end ensure + # Make sure we forget the retained module_directories of any autoload + # we might have used. + Thread.current[:env_module_directories] = nil + # Now close all of our existing http connections, since there's no # reason to leave them lying open. Puppet::Network::HttpPool.clear_http_instances execute_postrun_command Puppet::Util::Log.close(report) - send_report(report, transaction) end def send_report(report, trans = nil) trans.generate_report if trans puts report.summary if Puppet[:summarize] - report.save if Puppet[:report] + save_last_run_summary(report) + if Puppet[:report] + report.save + end rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not send report: #{detail}" end + def save_last_run_summary(report) + Puppet::Util::FileLocking.writelock(Puppet[:lastrunfile], 0660) do |file| + file.print YAML.dump(report.raw_summary) + end + rescue => detail + puts detail.backtrace if Puppet[:trace] + Puppet.err "Could not save last run local report: #{detail}" + end + private def self.timeout diff --git a/lib/puppet/daemon.rb b/lib/puppet/daemon.rb index aa4a12bfa..c76d63a54 100755 --- a/lib/puppet/daemon.rb +++ b/lib/puppet/daemon.rb @@ -43,7 +43,7 @@ class Puppet::Daemon # Create a pidfile for our daemon, so we can be stopped and others # don't try to start. def create_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock end end @@ -73,7 +73,7 @@ class Puppet::Daemon # Remove the pid file for our daemon. def remove_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do locker = Puppet::Util::Pidlock.new(pidfile) locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked? end @@ -121,8 +121,8 @@ class Puppet::Daemon create_pidfile raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server - agent.start if agent server.start if server + agent.start if agent EventLoop.current.run end diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 84e2d93fc..8bf1cd84d 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -2,12 +2,12 @@ module Puppet setdefaults(:main, :confdir => [Puppet.run_mode.conf_dir, "The main Puppet configuration directory. The default for this parameter is calculated based on the user. If the process - is running as root or the user that ``puppet master`` is supposed to run as, it defaults to a system directory, but if it's running as any other user, - it defaults to being in ``~``."], + is running as root or the user that `puppet master` is supposed to run as, it defaults to a system directory, but if it's running as any other user, + it defaults to being in `~`."], :vardir => [Puppet.run_mode.var_dir, "Where Puppet stores dynamic and growing data. The default for this parameter is calculated specially, like `confdir`_."], :name => [Puppet.application_name.to_s, "The name of the application, if we are running as one. The - default is essentially $0 without the path or ``.rb``."], - :mode => [Puppet.run_mode.name.to_s, "The effective 'run mode' of the application: master, agent, or user."] + default is essentially $0 without the path or `.rb`."], + :run_mode => [Puppet.run_mode.name.to_s, "The effective 'run mode' of the application: master, agent, or user."] ) setdefaults(:main, :logdir => Puppet.run_mode.logopts) @@ -44,8 +44,8 @@ module Puppet specify 'all'. This feature is only available in Puppet versions higher than 0.18.4."], :color => ["ansi", "Whether to use colors when logging to the console. - Valid values are ``ansi`` (equivalent to ``true``), ``html`` (mostly - used during testing with TextMate), and ``false``, which produces + Valid values are `ansi` (equivalent to `true`), `html` (mostly + used during testing with TextMate), and `false`, which produces no color."], :mkusers => [false, "Whether to create the necessary user and group that puppet agent will @@ -92,18 +92,18 @@ module Puppet :authconfig => [ "$confdir/namespaceauth.conf", "The configuration file that defines the rights to the different namespaces and methods. This can be used as a coarse-grained - authorization system for both ``puppet agent`` and ``puppet master``." + authorization system for both `puppet agent` and `puppet master`." ], :environment => {:default => "production", :desc => "The environment Puppet is running in. For clients - (e.g., ``puppet agent``) this determines the environment itself, which - is used to find modules and much more. For servers (i.e., ``puppet master``) this provides the default environment for nodes + (e.g., `puppet agent`) this determines the environment itself, which + is used to find modules and much more. For servers (i.e., `puppet master`) this provides the default environment for nodes we know nothing about." }, :diff_args => ["-u", "Which arguments to pass to the diff command when printing differences between files."], :diff => ["diff", "Which diff command to use when printing differences between files."], :show_diff => [false, "Whether to print a contextual diff when files are being replaced. The diff is printed on stdout, so this option is meaningless unless you are running Puppet interactively. - This feature currently requires the ``diff/lcs`` Ruby library."], + This feature currently requires the `diff/lcs` Ruby library."], :daemonize => { :default => true, :desc => "Send the process into the background. This is the default.", :short => "D" @@ -115,7 +115,17 @@ module Puppet :node_terminus => ["plain", "Where to find information about nodes."], :catalog_terminus => ["compiler", "Where to get node catalogs. This is useful to change if, for instance, you'd like to pre-compile catalogs and store them in memcached or some other easily-accessed store."], - :facts_terminus => ["facter", "Where to get node facts."], + :facts_terminus => { + :default => Puppet.application_name.to_s == "master" ? 'yaml' : 'facter', + :desc => "The node facts terminus.", + :hook => proc do |value| + require 'puppet/node/facts' + if value.to_s == "rest" + Puppet::Node::Facts.cache_class = :yaml + end + end + }, + :inventory_terminus => [ "$facts_terminus", "Should usually be the same as the facts terminus" ], :httplog => { :default => "$logdir/http.log", :owner => "root", :mode => 0640, @@ -135,7 +145,7 @@ module Puppet :queue_source => ["stomp://localhost:61613/", "Which type of queue to use for asynchronous processing. If your stomp server requires authentication, you can include it in the URI as long as your stomp client library is at least 1.1.1"], :async_storeconfigs => {:default => false, :desc => "Whether to use a queueing system to provide asynchronous database integration. - Requires that ``puppetqd`` be running and that 'PSON' support for ruby be installed.", + Requires that `puppetqd` be running and that 'PSON' support for ruby be installed.", :hook => proc do |value| if value # This reconfigures the terminii for Node, Facts, and Catalog @@ -266,10 +276,9 @@ module Puppet to all clients. If enabled, CA chaining will almost definitely not work."] ) - setdefaults( :ca, - :ca_name => ["$certname", "The name to use the Certificate Authority certificate."], + :ca_name => ["Puppet CA: $certname", "The name to use the Certificate Authority certificate."], :cadir => { :default => "$ssldir/ca", :owner => "service", :group => "service", @@ -385,7 +394,7 @@ module Puppet :manifestdir => ["$confdir/manifests", "Where puppet master looks for its manifests."], :manifest => ["$manifestdir/site.pp", "The entry-point manifest for puppet master."], :code => ["", "Code to parse directly. This is essentially only used - by ``puppet``, and should only be set if you're writing your own Puppet + by `puppet`, and should only be set if you're writing your own Puppet executable"], :masterlog => { :default => "$logdir/puppetmaster.log", :owner => "service", @@ -419,7 +428,7 @@ module Puppet :rest_authconfig => [ "$confdir/auth.conf", "The configuration file that defines the rights to the different rest indirections. This can be used as a fine-grained - authorization system for ``puppet master``." + authorization system for `puppet master`." ], :ca => [true, "Wether the master should function as a certificate authority."], :modulepath => {:default => "$confdir/modules:/usr/share/puppet/modules", @@ -427,7 +436,7 @@ module Puppet directories.", :type => :setting }, # We don't want this to be considered a file, since it's multiple files. :ssl_client_header => ["HTTP_X_CLIENT_DN", "The header containing an authenticated client's SSL DN. Only used with Mongrel. This header must be set by the proxy - to the authenticated client's SSL DN (e.g., ``/CN=puppet.puppetlabs.com``). + to the authenticated client's SSL DN (e.g., `/CN=puppet.puppetlabs.com`). See http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel for more information."], :ssl_client_verify_header => ["HTTP_X_CLIENT_VERIFY", "The header containing the status message of the client verification. Only used with Mongrel. This header must be set by the proxy @@ -441,10 +450,25 @@ module Puppet :desc => "The directory in which serialized data is stored, usually in a subdirectory."}, :reports => ["store", "The list of reports to generate. All reports are looked for - in puppet/reports/name.rb, and multiple report names should be + in `puppet/reports/name.rb`, and multiple report names should be comma-separated (whitespace is okay)." ], + :reportdir => {:default => "$vardir/reports", + :mode => 0750, + :owner => "service", + :group => "service", + :desc => "The directory in which to store reports + received from the client. Each client gets a separate + subdirectory."}, + :reporturl => ["http://localhost:3000/reports", + "The URL used by the http reports processor to send reports"], :fileserverconfig => ["$confdir/fileserver.conf", "Where the fileserver configuration is stored."], + :strict_hostname_checking => [false, "Whether to only search for the complete + hostname as it is in the certificate when searching for node information + in the catalogs."] + ) + + setdefaults(:metrics, :rrddir => {:default => "$vardir/rrd", :owner => "service", :group => "service", @@ -453,10 +477,7 @@ module Puppet this directory." }, :rrdinterval => ["$runinterval", "How often RRD should expect data. - This should match how often the hosts report back to the server."], - :strict_hostname_checking => [false, "Whether to only search for the complete - hostname as it is in the certificate when searching for node information - in the catalogs."] + This should match how often the hosts report back to the server."] ) setdefaults(:agent, @@ -479,7 +500,7 @@ module Puppet :mode => 0644, :desc => "The file in which puppet agent stores a list of the classes associated with the retrieved configuration. Can be loaded in - the separate ``puppet`` executable using the ``--loadclasses`` + the separate `puppet` executable using the `--loadclasses` option."}, :puppetdlog => { :default => "$logdir/puppetd.log", :owner => "root", @@ -496,8 +517,8 @@ module Puppet "How often puppet agent applies the client configuration; in seconds."], :listen => [false, "Whether puppet agent should listen for connections. If this is true, then by default only the - ``runner`` server is started, which allows remote authorized - and authenticated nodes to connect and trigger ``puppet agent`` + `runner` server is started, which allows remote authorized + and authenticated nodes to connect and trigger `puppet agent` runs."], :ca_server => ["$server", "The server to use for certificate authority requests. It's a separate server because it cannot @@ -567,14 +588,28 @@ module Puppet end }, :report_server => ["$server", - "The server to which to send transaction reports." + "The server to send transaction reports to." ], :report_port => ["$masterport", "The port to communicate with the report_server." ], - :report => [false, + :inventory_server => ["$server", + "The server to send facts to." + ], + :inventory_port => ["$masterport", + "The port to communicate with the inventory_server." + ], + :report => [true, "Whether to send reports after every transaction." ], + :lastrunfile => { :default => "$statedir/last_run_summary.yaml", + :mode => 0660, + :desc => "Where puppet agent stores the last run report summary in yaml format." + }, + :lastrunreport => { :default => "$statedir/last_run_report.yaml", + :mode => 0660, + :desc => "Where puppet agent stores the last run report in yaml format." + }, :graph => [false, "Whether to create dot graph files for the different configuration graphs. These dot files can be interpreted by tools like OmniGraffle or dot (which is part of ImageMagick)."], @@ -595,7 +630,7 @@ module Puppet "Where Puppet should store plugins that it pulls down from the central server."], :pluginsource => ["puppet://$server/plugins", - "From where to retrieve plugins. The standard Puppet ``file`` type + "From where to retrieve plugins. The standard Puppet `file` type is used for retrieval, so anything that is a valid file source can be used here."], :pluginsync => [false, "Whether plugins should be synced with the central server."], @@ -607,7 +642,7 @@ module Puppet setdefaults( :main, - :factpath => {:default => "$vardir/lib/facter/${File::PATH_SEPARATOR}$vardir/facts", + :factpath => {:default => "$vardir/lib/facter:$vardir/facts", :desc => "Where Puppet should look for facts. Multiple directories should be colon-separated, like normal PATH variables.", @@ -618,33 +653,23 @@ module Puppet "Where Puppet should store facts that it pulls down from the central server."], :factsource => ["puppet://$server/facts/", - "From where to retrieve facts. The standard Puppet ``file`` type + "From where to retrieve facts. The standard Puppet `file` type is used for retrieval, so anything that is a valid file source can be used here."], :factsync => [false, "Whether facts should be synced with the central server."], - :factsignore => [".svn CVS", "What files to ignore when pulling down facts."], - :reportdir => {:default => "$vardir/reports", - :mode => 0750, - :owner => "service", - :group => "service", - :desc => "The directory in which to store reports - received from the client. Each client gets a separate - subdirectory."}, - :reporturl => ["http://localhost:3000/reports", - "The URL used by the http reports processor to send reports"] + :factsignore => [".svn CVS", "What files to ignore when pulling down facts."] ) setdefaults( :tagmail, :tagmap => ["$confdir/tagmail.conf", "The mapping between reporting tags and email addresses."], - :sendmail => [%x{which sendmail 2>/dev/null}.chomp, "Where to find the sendmail binary with which to send email."], + :sendmail => [which('sendmail') || '', "Where to find the sendmail binary with which to send email."], :reportfrom => ["report@" + [Facter["hostname"].value, Facter["domain"].value].join("."), "The 'from' email address for the reports."], :smtpserver => ["none", "The server through which to send email reports."] ) - setdefaults( :rails, :dblocation => { :default => "$statedir/clientconfigs.sqlite3", @@ -665,11 +690,10 @@ module Puppet used when networked databases are used."], :dbpassword => [ "puppet", "The database password for caching. Only used when networked databases are used."], + :dbconnections => [ '', "The number of database connections for networked + databases. Will be ignored unless the value is a positive integer."], :dbsocket => [ "", "The database socket location. Only used when networked databases are used. Will be ignored if the value is an empty string."], - :dbconnections => [ 0, "The number of database connections. Only used when - networked databases are used. Will be ignored if the value is an empty - string or is less than 1."], :railslog => {:default => "$logdir/rails.log", :mode => 0600, :owner => "service", @@ -678,18 +702,16 @@ module Puppet }, :rails_loglevel => ["info", "The log level for Rails connections. The value must be - a valid log level within Rails. Production environments normally use ``info`` - and other environments normally use ``debug``."] + a valid log level within Rails. Production environments normally use `info` + and other environments normally use `debug`."] ) - setdefaults( :couchdb, :couchdb_url => ["http://127.0.0.1:5984/puppet", "The url where the puppet couchdb database will be created"] ) - setdefaults( :transaction, :tags => ["", "Tags to use to find resources. If this is set, then @@ -704,21 +726,19 @@ module Puppet ] ) - setdefaults( :main, :external_nodes => ["none", "An external command that can produce node information. The output must be a YAML dump of a hash, and that hash must have one or both of - ``classes`` and ``parameters``, where ``classes`` is an array and - ``parameters`` is a hash. For unknown nodes, the commands should + `classes` and `parameters`, where `classes` is an array and + `parameters` is a hash. For unknown nodes, the commands should exit with a non-zero exit code. This command makes it straightforward to store your node mapping information in other data sources like databases."]) - setdefaults( :ldap, :ldapnodes => [false, @@ -733,9 +753,9 @@ module Puppet Defaults to false because TLS usually requires certificates to be set up on the client side."], :ldapserver => ["ldap", - "The LDAP server. Only used if ``ldapnodes`` is enabled."], + "The LDAP server. Only used if `ldapnodes` is enabled."], :ldapport => [389, - "The LDAP port. Only used if ``ldapnodes`` is enabled."], + "The LDAP port. Only used if `ldapnodes` is enabled."], :ldapstring => ["(&(objectclass=puppetClient)(cn=%s))", "The search string used to find an LDAP node."], diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb index abdb78f67..97a310436 100644 --- a/lib/puppet/dsl.rb +++ b/lib/puppet/dsl.rb @@ -5,7 +5,3 @@ end require 'puppet/dsl/resource_type_api' require 'puppet/dsl/resource_api' - -class Object - include Puppet::DSL::ResourceTypeAPI -end diff --git a/lib/puppet/dsl/resource_type_api.rb b/lib/puppet/dsl/resource_type_api.rb index 487aab99d..8810d5368 100644 --- a/lib/puppet/dsl/resource_type_api.rb +++ b/lib/puppet/dsl/resource_type_api.rb @@ -1,34 +1,15 @@ require 'puppet/resource/type' -module Puppet::DSL::ResourceTypeAPI - def define(name, *args, &block) - result = mk_resource_type(:definition, name, Hash.new, block) - result.set_arguments(munge_type_arguments(args)) - result - end - - def hostclass(name, options = {}, &block) - mk_resource_type(:hostclass, name, options, block) - end - - def node(name, options = {}, &block) - mk_resource_type(:node, name, options, block) - end - - private - - def mk_resource_type(type, name, options, code) - klass = Puppet::Resource::Type.new(type, name, options) - - klass.ruby_code = code if code - - Puppet::Node::Environment.new.known_resource_types.add klass - - klass +# Type of the objects inside of which pure ruby manifest files are +# executed. Provides methods for creating defines, hostclasses, and +# nodes. +class Puppet::DSL::ResourceTypeAPI + def initialize + @__created_ast_objects__ = [] end - def munge_type_arguments(args) - args.inject([]) do |result, item| + def define(name, *args, &block) + args = args.inject([]) do |result, item| if item.is_a?(Hash) item.each { |p, v| result << [p, v] } else @@ -36,5 +17,18 @@ module Puppet::DSL::ResourceTypeAPI end result end + @__created_ast_objects__.push Puppet::Parser::AST::Definition.new(name, {:arguments => args}, &block) + nil + end + + def hostclass(name, options = {}, &block) + @__created_ast_objects__.push Puppet::Parser::AST::Hostclass.new(name, options, &block) + nil + end + + def node(name, options = {}, &block) + name = [name] unless name.is_a?(Array) + @__created_ast_objects__.push Puppet::Parser::AST::Node.new(name, options, &block) + nil end end diff --git a/lib/puppet/external/event-loop/event-loop.rb b/lib/puppet/external/event-loop/event-loop.rb index dc51a55ae..3b40f6e71 100644 --- a/lib/puppet/external/event-loop/event-loop.rb +++ b/lib/puppet/external/event-loop/event-loop.rb @@ -75,8 +75,10 @@ class EventLoop @notify_src, @notify_snk = IO.pipe # prevent file descriptor leaks - @notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) - @notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + if @notify_src.respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_SETFD) and defined?(Fcntl::FD_CLOEXEC) + @notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + @notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) + end @notify_src.will_block = false @notify_snk.will_block = false @@ -234,19 +236,21 @@ class IO end def will_block? - require "fcntl" - fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0 + if respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_GETFL) and defined?(Fcntl::O_NONBLOCK) + fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0 + end end def will_block= (wants_blocking) - require "fcntl" - flags = fcntl(Fcntl::F_GETFL, 0) - if wants_blocking - flags &= ~Fcntl::O_NONBLOCK - else - flags |= Fcntl::O_NONBLOCK + if respond_to?(:fcntl) and defined?(Fcntl) and defined?(Fcntl::F_GETFL) and defined?(Fcntl::O_NONBLOCK) + flags = fcntl(Fcntl::F_GETFL, 0) + if wants_blocking + flags &= ~Fcntl::O_NONBLOCK + else + flags |= Fcntl::O_NONBLOCK + end + fcntl(Fcntl::F_SETFL, flags) end - fcntl(Fcntl::F_SETFL, flags) end end diff --git a/lib/puppet/external/pson/pure/generator.rb b/lib/puppet/external/pson/pure/generator.rb index ef8b36d31..89a0c62e0 100644 --- a/lib/puppet/external/pson/pure/generator.rb +++ b/lib/puppet/external/pson/pure/generator.rb @@ -44,41 +44,13 @@ module PSON string << '' # XXX workaround: avoid buffer sharing string.force_encoding(Encoding::ASCII_8BIT) string.gsub!(/["\\\x0-\x1f]/) { MAP[$MATCH] } - string.gsub!(/( - (?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+ | - [\x80-\xc1\xf5-\xff] # invalid - )/nx) { |c| - c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'" - s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0] - s.gsub!(/.{4}/n, '\\\\u\&') - } - string.force_encoding(Encoding::UTF_8) string rescue Iconv::Failure => e raise GeneratorError, "Caught #{e.class}: #{e}" end else def utf8_to_pson(string) # :nodoc: - string = string.gsub(/["\\\x0-\x1f]/) { MAP[$MATCH] } - string.gsub!(/( - (?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+ | - [\x80-\xc1\xf5-\xff] # invalid - )/nx) { |c| - c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'" - s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0] - s.gsub!(/.{4}/n, '\\\\u\&') - } - string - rescue Iconv::Failure => e - raise GeneratorError, "Caught #{e.class}: #{e}" + string.gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] } end end module_function :utf8_to_pson diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb index c153fba98..c983f5c12 100644 --- a/lib/puppet/feature/base.rb +++ b/lib/puppet/feature/base.rb @@ -27,7 +27,8 @@ Puppet.features.add :diff, :libs => %w{diff/lcs diff/lcs/hunk} Puppet.features.add(:augeas, :libs => ["augeas"]) # We have RRD available -Puppet.features.add(:rrd, :libs => ["RRDtool"]) +Puppet.features.add(:rrd_legacy, :libs => ["RRDtool"]) +Puppet.features.add(:rrd, :libs => ["RRD"]) # We have OpenSSL Puppet.features.add(:openssl, :libs => ["openssl"]) diff --git a/lib/puppet/feature/rails.rb b/lib/puppet/feature/rails.rb index e0e14ebeb..74ed09aa6 100644 --- a/lib/puppet/feature/rails.rb +++ b/lib/puppet/feature/rails.rb @@ -24,9 +24,7 @@ Puppet.features.add(:rails) do end end - if ! (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR)) - false - elsif ! (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR >= 1) + unless (Puppet::Util.activerecord_version >= 2.1) Puppet.info "ActiveRecord 2.1 or later required for StoreConfigs" false else diff --git a/lib/puppet/file_serving/indirection_hooks.rb b/lib/puppet/file_serving/indirection_hooks.rb index 7e0c17916..a85e90ef1 100644 --- a/lib/puppet/file_serving/indirection_hooks.rb +++ b/lib/puppet/file_serving/indirection_hooks.rb @@ -19,8 +19,8 @@ module Puppet::FileServing::IndirectionHooks return PROTOCOL_MAP["file"] if request.key =~ /^#{::File::SEPARATOR}/ return PROTOCOL_MAP["file"] if request.protocol == "file" - # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'puppet' - if request.protocol == "puppet" and (request.server or Puppet.settings[:name] != "puppet") + # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'apply' or 'puppet' + if request.protocol == "puppet" and (request.server or !["puppet","apply"].include?(Puppet.settings[:name])) return PROTOCOL_MAP["puppet"] end diff --git a/lib/puppet/indirector/catalog/compiler.rb b/lib/puppet/indirector/catalog/compiler.rb index c50022fff..78be4caf7 100644 --- a/lib/puppet/indirector/catalog/compiler.rb +++ b/lib/puppet/indirector/catalog/compiler.rb @@ -22,6 +22,7 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code else facts = Puppet::Node::Facts.convert_from(format, text_facts) end + facts.add_timestamp facts.save end @@ -107,10 +108,14 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code return node end - # If the request is authenticated, then the 'node' info will - # be available; if not, then we use the passed-in key. We rely - # on our authorization system to determine whether this is allowed. - name = request.node || request.key + # We rely on our authorization system to determine whether the connected + # node is allowed to compile the catalog's node referenced by key. + # By default the REST authorization system makes sure only the connected node + # can compile his catalog. + # This allows for instance monitoring systems or puppet-load to check several + # node's catalog with only one certificate and a modification to auth.conf + # If no key is provided we can only compile the currently connected node. + name = request.key || request.node if node = find_node(name) return node end diff --git a/lib/puppet/indirector/facts/memory.rb b/lib/puppet/indirector/facts/memory.rb index c4ca19da5..93682f456 100644 --- a/lib/puppet/indirector/facts/memory.rb +++ b/lib/puppet/indirector/facts/memory.rb @@ -3,7 +3,7 @@ require 'puppet/indirector/memory' class Puppet::Node::Facts::Memory < Puppet::Indirector::Memory desc "Keep track of facts in memory but nowhere else. This is used for - one-time compiles, such as what the stand-alone ``puppet`` does. + one-time compiles, such as what the stand-alone `puppet` does. To use this terminus, you must load it with the data you want it to contain." end diff --git a/lib/puppet/indirector/facts/rest.rb b/lib/puppet/indirector/facts/rest.rb index 07491fc77..e2afa14b2 100644 --- a/lib/puppet/indirector/facts/rest.rb +++ b/lib/puppet/indirector/facts/rest.rb @@ -3,4 +3,6 @@ require 'puppet/indirector/rest' class Puppet::Node::Facts::Rest < Puppet::Indirector::REST desc "Find and save facts about nodes over HTTP via REST." + use_server_setting(:inventory_server) + use_port_setting(:inventory_port) end diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb index 309eed7b6..9095e48f8 100644 --- a/lib/puppet/indirector/indirection.rb +++ b/lib/puppet/indirector/indirection.rb @@ -238,6 +238,7 @@ class Puppet::Indirector::Indirection if result = terminus.search(request) raise Puppet::DevError, "Search results from terminus #{terminus.name} are not an array" unless result.is_a?(Array) result.each do |instance| + next unless instance.respond_to? :expiration instance.expiration ||= self.expiration end return result diff --git a/lib/puppet/indirector/inventory/yaml.rb b/lib/puppet/indirector/inventory/yaml.rb new file mode 100644 index 000000000..fe3489a95 --- /dev/null +++ b/lib/puppet/indirector/inventory/yaml.rb @@ -0,0 +1,81 @@ +require 'puppet/node/inventory' +require 'puppet/indirector/yaml' + +class Puppet::Node::Inventory::Yaml < Puppet::Indirector::Yaml + desc "Return node names matching the fact query" + + # Return the path to a given node's file. + def yaml_dir_path + base = Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir] + File.join(base, 'facts', '*.yaml') + end + + def node_matches?(facts, options) + options.each do |key, value| + type, name, operator = key.to_s.split(".") + operator ||= 'eq' + + return false unless node_matches_option?(type, name, operator, value, facts) + end + return true + end + + def search(request) + node_names = [] + Dir.glob(yaml_dir_path).each do |file| + facts = YAML.load_file(file) + node_names << facts.name if node_matches?(facts, request.options) + end + node_names + end + + private + + def node_matches_option?(type, name, operator, value, facts) + case type + when "meta" + case name + when "timestamp" + compare_timestamp(operator, facts.timestamp, Time.parse(value)) + end + when "facts" + compare_facts(operator, facts.values[name], value) + end + end + + def compare_facts(operator, value1, value2) + return false unless value1 + + case operator + when "eq" + value1.to_s == value2.to_s + when "le" + value1.to_f <= value2.to_f + when "ge" + value1.to_f >= value2.to_f + when "lt" + value1.to_f < value2.to_f + when "gt" + value1.to_f > value2.to_f + when "ne" + value1.to_s != value2.to_s + end + end + + def compare_timestamp(operator, value1, value2) + case operator + when "eq" + value1 == value2 + when "le" + value1 <= value2 + when "ge" + value1 >= value2 + when "lt" + value1 < value2 + when "gt" + value1 > value2 + when "ne" + value1 != value2 + end + end +end diff --git a/lib/puppet/indirector/node/exec.rb b/lib/puppet/indirector/node/exec.rb index c3e690943..6e065c6f3 100644 --- a/lib/puppet/indirector/node/exec.rb +++ b/lib/puppet/indirector/node/exec.rb @@ -3,7 +3,7 @@ require 'puppet/indirector/exec' class Puppet::Node::Exec < Puppet::Indirector::Exec desc "Call an external program to get node information. See - the `ExternalNodes`:trac: page for more information." + the [External Nodes](http://docs.puppetlabs.com/guides/external_nodes.html) page for more information." include Puppet::Util def command diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb index b9fe35575..5fd738511 100644 --- a/lib/puppet/indirector/node/ldap.rb +++ b/lib/puppet/indirector/node/ldap.rb @@ -3,9 +3,9 @@ require 'puppet/indirector/ldap' class Puppet::Node::Ldap < Puppet::Indirector::Ldap desc "Search in LDAP for node configuration information. See - the `LdapNodes`:trac: page for more information. This will first + the [LDAP Nodes](http://projects.puppetlabs.com/projects/puppet/wiki/Ldap_Nodes) page for more information. This will first search for whatever the certificate name is, then (if that name - contains a '.') for the short name, then 'default'." + contains a `.`) for the short name, then `default`." # The attributes that Puppet class information is stored in. def class_attributes @@ -19,30 +19,10 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap # LAK:NOTE Unfortunately, the ldap support is too stupid to throw anything # but LDAP::ResultError, even on bad connections, so we are rough handed # with our error handling. - def name2hash(name,name_env,node_type) + def name2hash(name) info = nil - ldapsearch(search_filter(name)) { - |entry| info = entry2hash(entry) - if info[:environment] - if name_env == info[:environment] - return info - else - info = nil - end - else - info_env = "production" - if name_env == info[:environment] - return info - else - info = nil - end - end - } - if node_type == 'parent' - raise Puppet::Error.new("Could not find node '#{name}' with environment '#{name_env}'") - end - - info = name2hash('default',name_env,'parent') + ldapsearch(search_filter(name)) { |entry| info = entry2hash(entry) } + info end # Look for our node in ldap. @@ -53,18 +33,9 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap node = nil names.each do |name| - facts = Puppet::Node::Facts.find(name) - if facts.values["environment"] - name_env = facts.values["environment"] - else - name_env = "production" - end - info = name2hash(name,name_env,'child') - next if info == nil + next unless info = name2hash(name) - if info - break if node = info2node(request.key, info) - end + break if node = info2node(request.key, info) end node @@ -200,29 +171,14 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap # Find information for our parent and merge it into the current info. def find_and_merge_parent(parent, information) - - if information[:environment] - name_env = information[:environment] - else - name_env = 'production' - end - - parent_info = name2hash(parent,name_env,'parent') - if parent_info + parent_info = name2hash(parent) || raise(Puppet::Error.new("Could not find parent node '#{parent}'")) information[:classes] += parent_info[:classes] parent_info[:parameters].each do |param, value| - # Specifically test for whether it's set, so false values are handled - # correctly. + # Specifically test for whether it's set, so false values are handled correctly. information[:parameters][param] = value unless information[:parameters].include?(param) end - information[:environment] ||= parent_info[:environment] parent_info[:parent] - else - raise Puppet::Error.new("Could not find parent node '#{parent}'") - nil - end - end # Take a name and a hash, and return a node instance. diff --git a/lib/puppet/indirector/node/memory.rb b/lib/puppet/indirector/node/memory.rb index ce4a52a8f..029926af8 100644 --- a/lib/puppet/indirector/node/memory.rb +++ b/lib/puppet/indirector/node/memory.rb @@ -3,7 +3,7 @@ require 'puppet/indirector/memory' class Puppet::Node::Memory < Puppet::Indirector::Memory desc "Keep track of nodes in memory but nowhere else. This is used for - one-time compiles, such as what the stand-alone ``puppet`` does. + one-time compiles, such as what the stand-alone `puppet` does. To use this terminus, you must load it with the data you want it to contain; it is only useful for developers and should generally not be chosen by a normal user." diff --git a/lib/puppet/indirector/report/yaml.rb b/lib/puppet/indirector/report/yaml.rb new file mode 100644 index 000000000..bf7bf4fe5 --- /dev/null +++ b/lib/puppet/indirector/report/yaml.rb @@ -0,0 +1,11 @@ +require 'puppet/transaction/report' +require 'puppet/indirector/yaml' + +class Puppet::Transaction::Report::Yaml < Puppet::Indirector::Yaml + desc "Store last report as a flat file, serialized using YAML." + + # Force report to be saved there + def path(name,ext='.yaml') + Puppet[:lastrunreport] + end +end diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb index c7c053f4b..23997e97a 100644 --- a/lib/puppet/indirector/yaml.rb +++ b/lib/puppet/indirector/yaml.rb @@ -41,19 +41,16 @@ class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus end end - # Get the yaml directory - def base - Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir] - end - # Return the path to a given node's file. - def path(name) - File.join(base, self.class.indirection_name.to_s, name.to_s + ".yaml") + def path(name,ext='.yaml') + base = Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir] + File.join(base, self.class.indirection_name.to_s, name.to_s + ext) end - # Do a glob on the yaml directory, loading each file found def search(request) - Dir.glob(File.join(base, self.class.indirection_name.to_s, request.key)).collect { |f| YAML.load_file(f) } + Dir.glob(path(request.key,'')).collect do |file| + YAML.load_file(file) + end end private diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/network/format_handler.rb index d378ad6a1..b94a4f902 100644 --- a/lib/puppet/network/format_handler.rb +++ b/lib/puppet/network/format_handler.rb @@ -37,6 +37,12 @@ module Puppet::Network::FormatHandler instance end + def self.create_serialized_formats(name,options = {},&block) + ["application/x-#{name}", "application/#{name}", "text/x-#{name}", "text/#{name}"].each { |mime_type| + create name, {:mime => mime_type}.update(options), &block + } + end + def self.extended(klass) klass.extend(ClassMethods) diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb index 8a61ee62a..4ca3240d4 100644 --- a/lib/puppet/network/formats.rb +++ b/lib/puppet/network/formats.rb @@ -1,6 +1,6 @@ require 'puppet/network/format_handler' -Puppet::Network::FormatHandler.create(:yaml, :mime => "text/yaml") do +Puppet::Network::FormatHandler.create_serialized_formats(:yaml) do # Yaml doesn't need the class name; it's serialized. def intern(klass, text) YAML.load(text) @@ -29,7 +29,7 @@ end # This is a "special" format which is used for the moment only when sending facts # as REST GET parameters (see Puppet::Configurer::FactHandler). # This format combines a yaml serialization, then zlib compression and base64 encoding. -Puppet::Network::FormatHandler.create(:b64_zlib_yaml, :mime => "text/b64_zlib_yaml") do +Puppet::Network::FormatHandler.create_serialized_formats(:b64_zlib_yaml) do require 'base64' def use_zlib? @@ -127,7 +127,7 @@ Puppet::Network::FormatHandler.create(:raw, :mime => "application/x-raw", :weigh end end -Puppet::Network::FormatHandler.create(:pson, :mime => "text/pson", :weight => 10, :required_methods => [:render_method, :intern_method]) do +Puppet::Network::FormatHandler.create_serialized_formats(:pson, :weight => 10, :required_methods => [:render_method, :intern_method]) do confine :true => Puppet.features.pson? def intern(klass, text) @@ -159,4 +159,4 @@ Puppet::Network::FormatHandler.create(:pson, :mime => "text/pson", :weight => 10 end # This is really only ever going to be used for Catalogs. -Puppet::Network::FormatHandler.create(:dot, :mime => "text/dot", :required_methods => [:render_method]) +Puppet::Network::FormatHandler.create_serialized_formats(:dot, :required_methods => [:render_method]) diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index 27b913ab9..9abc7ee1a 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -4,9 +4,13 @@ require 'webrick/httpstatus' require 'cgi' require 'delegate' require 'sync' +require 'xmlrpc/server' +require 'puppet/network/handler' +require 'puppet/network/xmlrpc/server' require 'puppet/file_serving' require 'puppet/file_serving/metadata' +require 'puppet/network/handler' class Puppet::Network::Handler AuthStoreError = Puppet::AuthStoreError diff --git a/lib/puppet/network/http/api/v1.rb b/lib/puppet/network/http/api/v1.rb index dd4612a14..abbb2dfa9 100644 --- a/lib/puppet/network/http/api/v1.rb +++ b/lib/puppet/network/http/api/v1.rb @@ -30,7 +30,7 @@ module Puppet::Network::HTTP::API::V1 key = URI.unescape(key) - Puppet::Indirector::Request.new(indirection, method, key, params) + [indirection, method, key, params] end def indirection2uri(request) @@ -57,9 +57,8 @@ module Puppet::Network::HTTP::API::V1 # fix to not need this, and our goal is to move away from the complication # that leads to the fix being too long. return :singular if indirection == "facts" - - # "status" really is singular return :singular if indirection == "status" + return :plural if indirection == "inventory" result = (indirection =~ /s$/) ? :plural : :singular diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb index 03d24b3fe..82238aa0a 100644 --- a/lib/puppet/network/http/handler.rb +++ b/lib/puppet/network/http/handler.rb @@ -61,11 +61,11 @@ module Puppet::Network::HTTP::Handler # handle an HTTP request def process(request, response) - indirection_request = uri2indirection(http_method(request), path(request), params(request)) + indirection, method, key, params = uri2indirection(http_method(request), path(request), params(request)) - check_authorization(indirection_request) + check_authorization(indirection, method, key, params) - send("do_#{indirection_request.method}", indirection_request, request, response) + send("do_#{method}", indirection, key, params, request, response) rescue SystemExit,NoMemoryError raise rescue Exception => e @@ -96,11 +96,16 @@ module Puppet::Network::HTTP::Handler set_response(response, exception.to_s, status) end + def model(indirection_name) + raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless indirection = Puppet::Indirector::Indirection.instance(indirection_name.to_sym) + indirection.model + end + # Execute our find. - def do_find(indirection_request, request, response) - unless result = indirection_request.model.find(indirection_request.key, indirection_request.to_hash) - Puppet.info("Could not find #{indirection_request.indirection_name} for '#{indirection_request.key}'") - return do_exception(response, "Could not find #{indirection_request.indirection_name} #{indirection_request.key}", 404) + def do_find(indirection_name, key, params, request, response) + unless result = model(indirection_name).find(key, params) + Puppet.info("Could not find #{indirection_name} for '#{key}'") + return do_exception(response, "Could not find #{indirection_name} #{key}", 404) end # The encoding of the result must include the format to use, @@ -113,34 +118,35 @@ module Puppet::Network::HTTP::Handler end # Execute our search. - def do_search(indirection_request, request, response) - result = indirection_request.model.search(indirection_request.key, indirection_request.to_hash) + def do_search(indirection_name, key, params, request, response) + model = self.model(indirection_name) + result = model.search(key, params) - if result.nil? or (result.is_a?(Array) and result.empty?) - return do_exception(response, "Could not find instances in #{indirection_request.indirection_name} with '#{indirection_request.to_hash.inspect}'", 404) + if result.nil? + return do_exception(response, "Could not find instances in #{indirection_name} with '#{key}'", 404) end format = format_to_use(request) set_content_type(response, format) - set_response(response, indirection_request.model.render_multiple(format, result)) + set_response(response, model.render_multiple(format, result)) end # Execute our destroy. - def do_destroy(indirection_request, request, response) - result = indirection_request.model.destroy(indirection_request.key, indirection_request.to_hash) + def do_destroy(indirection_name, key, params, request, response) + result = model(indirection_name).destroy(key, params) return_yaml_response(response, result) end # Execute our save. - def do_save(indirection_request, request, response) + def do_save(indirection_name, key, params, request, response) data = body(request).to_s raise ArgumentError, "No data to save" if !data or data.empty? format = request_format(request) - obj = indirection_request.model.convert_from(format, data) - result = save_object(indirection_request, obj) + obj = model(indirection_name).convert_from(format, data) + result = obj.save(key) return_yaml_response(response, result) end @@ -162,12 +168,6 @@ module Puppet::Network::HTTP::Handler set_response(response, body.to_yaml) end - # LAK:NOTE This has to be here for testing; it's a stub-point so - # we keep infinite recursion from happening. - def save_object(ind_request, object) - object.save(ind_request.key) - end - def get?(request) http_method(request) == 'GET' end diff --git a/lib/puppet/network/http/rack.rb b/lib/puppet/network/http/rack.rb index c18a07559..5b4ef7e1c 100644 --- a/lib/puppet/network/http/rack.rb +++ b/lib/puppet/network/http/rack.rb @@ -1,3 +1,6 @@ +require 'rack' +require 'rack/request' +require 'rack/response' require 'puppet/network/http' require 'puppet/network/http/rack/rest' diff --git a/lib/puppet/network/http/rack/rest.rb b/lib/puppet/network/http/rack/rest.rb index e5f50c465..b7e1d9709 100644 --- a/lib/puppet/network/http/rack/rest.rb +++ b/lib/puppet/network/http/rack/rest.rb @@ -41,7 +41,7 @@ class Puppet::Network::HTTP::RackREST < Puppet::Network::HTTP::RackHttpHandler unless result.is_a?(File) response.write result else - response["Content-Length"] = result.stat.size + response["Content-Length"] = result.stat.size.to_s response.body = RackFile.new(result) end end diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb index 91008aa1a..d5c146d88 100644 --- a/lib/puppet/network/http/webrick/rest.rb +++ b/lib/puppet/network/http/webrick/rest.rb @@ -1,5 +1,6 @@ require 'puppet/network/http/handler' require 'resolv' +require 'webrick' class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb index a3b055572..7d227b4d4 100644 --- a/lib/puppet/network/http_pool.rb +++ b/lib/puppet/network/http_pool.rb @@ -58,18 +58,6 @@ module Puppet::Network::HttpPool http.cert = ssl_host.certificate.content http.verify_mode = OpenSSL::SSL::VERIFY_PEER http.key = ssl_host.key.content - http.verify_callback = self.method(:ssl_verify_callback).to_proc if Puppet[:debug] - end - - def self.ssl_verify_callback(peer_ok, x509_store_ctx) - if not peer_ok - Puppet.debug "OpenSSL: Error(#{x509_store_ctx.error}): #{x509_store_ctx.error_string}" - Puppet.debug "OpenSSL: Cert: #{x509_store_ctx.current_cert.issuer}" - Puppet.debug "OpenSSL: Current CRL: #{x509_store_ctx.current_crl}" - Puppet.debug "OpenSSL: Chain:" - x509_store_ctx.chain.each_index { |i| Puppet.debug "OpenSSL: \t#{i} #{x509_store_ctx.chain[i].issuer}" } - end - peer_ok end # Retrieve a cached http instance if caching is enabled, else return diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb index 38a8f9a09..b6a163316 100644 --- a/lib/puppet/network/rest_authconfig.rb +++ b/lib/puppet/network/rest_authconfig.rb @@ -3,6 +3,7 @@ require 'puppet/network/authconfig' module Puppet class Network::RestAuthConfig < Network::AuthConfig + extend MonitorMixin attr_accessor :rights DEFAULT_ACL = [ @@ -20,30 +21,32 @@ module Puppet ] def self.main - add_acl = @main.nil? - super - @main.insert_default_acl if add_acl and !@main.exists? + synchronize do + add_acl = @main.nil? + super + @main.insert_default_acl if add_acl and !@main.exists? + end @main end # check wether this request is allowed in our ACL # raise an Puppet::Network::AuthorizedError if the request # is denied. - def allowed?(request) + def allowed?(indirection, method, key, params) read # we're splitting the request in part because # fail_on_deny could as well be called in the XMLRPC context # with a ClientRequest. - @rights.fail_on_deny( - build_uri(request), - - :node => request.node, - :ip => request.ip, - :method => request.method, - :environment => request.environment, - :authenticated => request.authenticated) + @rights.fail_on_deny( + build_uri(indirection, key), + :node => params[:node], + :ip => params[:ip], + :method => method, + :environment => params[:environment], + :authenticated => params[:authenticated] + ) end def initialize(file = nil, parsenow = true) @@ -87,8 +90,8 @@ module Puppet @rights.restrict_authenticated(acl[:acl], acl[:authenticated]) unless acl[:authenticated].nil? end - def build_uri(request) - "/#{request.indirection_name}/#{request.key}" + def build_uri(indirection_name, key) + "/#{indirection_name}/#{key}" end end end diff --git a/lib/puppet/network/rest_authorization.rb b/lib/puppet/network/rest_authorization.rb index e052245eb..50f094e3e 100644 --- a/lib/puppet/network/rest_authorization.rb +++ b/lib/puppet/network/rest_authorization.rb @@ -15,8 +15,8 @@ module Puppet::Network end # Verify that our client has access. - def check_authorization(request) - authconfig.allowed?(request) + def check_authorization(indirection, method, key, params) + authconfig.allowed?(indirection, method, key, params) end end end diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb index d424b9c4a..e4de07dea 100644 --- a/lib/puppet/network/server.rb +++ b/lib/puppet/network/server.rb @@ -32,14 +32,14 @@ class Puppet::Network::Server # Create a pidfile for our daemon, so we can be stopped and others # don't try to start. def create_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock end end # Remove the pid file for our daemon. def remove_pidfile - Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do + Puppet::Util.synchronize_on(Puppet[:name],Sync::EX) do locker = Puppet::Util::Pidlock.new(pidfile) locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked? end diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb index 2453cd1d5..e8d58e6be 100644 --- a/lib/puppet/node.rb +++ b/lib/puppet/node.rb @@ -3,6 +3,7 @@ require 'puppet/indirector' # A class for managing nodes, including their facts and environment. class Puppet::Node require 'puppet/node/facts' + require 'puppet/node/inventory' require 'puppet/node/environment' # Set up indirection, so that nodes can be looked for in diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index 762599cff..7877b7f73 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -1,4 +1,5 @@ require 'puppet/util/cacher' +require 'monitor' # Just define it, so this class has fewer load dependencies. class Puppet::Node @@ -67,14 +68,23 @@ class Puppet::Node::Environment def initialize(name) @name = name + extend MonitorMixin end def known_resource_types - if @known_resource_types.nil? or @known_resource_types.stale? - @known_resource_types = Puppet::Resource::TypeCollection.new(self) - @known_resource_types.perform_initial_import - end - @known_resource_types + # This makes use of short circuit evaluation to get the right thread-safe + # per environment semantics with an efficient most common cases; we almost + # always just return our thread's known-resource types. Only at the start + # of a compilation (after our thread var has been set to nil) or when the + # environment has changed do we delve deeper. + Thread.current[:known_resource_types] = nil if (krt = Thread.current[:known_resource_types]) && krt.environment != self + Thread.current[:known_resource_types] ||= synchronize { + if @known_resource_types.nil? or @known_resource_types.stale? + @known_resource_types = Puppet::Resource::TypeCollection.new(self) + @known_resource_types.import_ast(perform_initial_import, '') + end + @known_resource_types + } end def module(name) @@ -114,6 +124,10 @@ class Puppet::Node::Environment name.to_s end + def to_sym + to_s.to_sym + end + # The only thing we care about when serializing an environment is its # identity; everything else is ephemeral and should not be stored or # transmitted. @@ -133,5 +147,31 @@ class Puppet::Node::Environment end end + private + + def perform_initial_import + return empty_parse_result if Puppet.settings[:ignoreimport] + parser = Puppet::Parser::Parser.new(self) + if code = Puppet.settings.uninterpolated_value(:code, name.to_s) and code != "" + parser.string = code + else + file = Puppet.settings.value(:manifest, name.to_s) + return empty_parse_result unless File.exist?(file) + parser.file = file + end + parser.parse + rescue => detail + msg = "Could not parse for environment #{self}: #{detail}" + error = Puppet::Error.new(msg) + error.set_backtrace(detail.backtrace) + raise error + end + + def empty_parse_result + # Return an empty toplevel hostclass to use as the result of + # perform_initial_import when no file was actually loaded. + return Puppet::Parser::AST::Hostclass.new('') + end + @root = new(:'*root*') end diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb index b77ad22d5..d84d54113 100755 --- a/lib/puppet/node/facts.rb +++ b/lib/puppet/node/facts.rb @@ -1,12 +1,17 @@ +require 'time' + require 'puppet/node' require 'puppet/indirector' +require 'puppet/util/pson' + # Manage a given node's facts. This either accepts facts and stores them, or # returns facts for a given node. class Puppet::Node::Facts # Set up indirection, so that nodes can be looked for in # the node sources. extend Puppet::Indirector + extend Puppet::Util::Pson # We want to expire any cached nodes if the facts are saved. module NodeExpirer @@ -30,7 +35,7 @@ class Puppet::Node::Facts @name = name @values = values - add_internal + add_timestamp end def downcase_if_necessary @@ -54,13 +59,37 @@ class Puppet::Node::Facts strip_internal == other.send(:strip_internal) end - private + def self.from_pson(data) + result = new(data['name'], data['values']) + result.values[:_timestamp] = Time.parse(data['timestamp']) + result.expiration = Time.parse(data['expiration']) + result + end + + def to_pson(*args) + { + 'expiration' => expiration, + 'name' => name, + 'timestamp' => values[:_timestamp], + 'values' => values.reject {|k,v| k == :_timestamp}, + }.to_pson(*args) + end # Add internal data to the facts for storage. - def add_internal - self.values[:_timestamp] = Time.now + def add_timestamp + self.timestamp = Time.now end + def timestamp=(time) + self.values[:_timestamp] = time + end + + def timestamp + self.values[:_timestamp] + end + + private + # Strip out that internal data. def strip_internal newvals = values.dup diff --git a/lib/puppet/node/inventory.rb b/lib/puppet/node/inventory.rb new file mode 100644 index 000000000..fd99163b0 --- /dev/null +++ b/lib/puppet/node/inventory.rb @@ -0,0 +1,7 @@ +require 'puppet/node' +require 'puppet/indirector' + +class Puppet::Node::Inventory + extend Puppet::Indirector + indirects :inventory, :terminus_setting => :inventory_terminus +end diff --git a/lib/puppet/parameter/value_collection.rb b/lib/puppet/parameter/value_collection.rb index a9fd20233..619e0731d 100644 --- a/lib/puppet/parameter/value_collection.rb +++ b/lib/puppet/parameter/value_collection.rb @@ -21,14 +21,14 @@ class Puppet::Parameter::ValueCollection @doc += " Valid values are " @doc += @strings.collect do |value| if aliases = value.aliases and ! aliases.empty? - "``#{value.name}`` (also called ``#{aliases.join(", ")}``)" + "`#{value.name}` (also called `#{aliases.join(", ")}`)" else - "``#{value.name}``" + "`#{value.name}`" end end.join(", ") + "." end - @doc += " Values can match ``" + regexes.join("``, ``") + "``." unless regexes.empty? + @doc += " Values can match `" + regexes.join("`, `") + "`." unless regexes.empty? end @doc diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb index 54e034acb..03891160b 100644 --- a/lib/puppet/parser/ast.rb +++ b/lib/puppet/parser/ast.rb @@ -107,28 +107,32 @@ end require 'puppet/parser/ast/arithmetic_operator' require 'puppet/parser/ast/astarray' require 'puppet/parser/ast/asthash' -require 'puppet/parser/ast/branch' require 'puppet/parser/ast/boolean_operator' +require 'puppet/parser/ast/branch' require 'puppet/parser/ast/caseopt' require 'puppet/parser/ast/casestatement' require 'puppet/parser/ast/collection' require 'puppet/parser/ast/collexpr' require 'puppet/parser/ast/comparison_operator' +require 'puppet/parser/ast/definition' require 'puppet/parser/ast/else' require 'puppet/parser/ast/function' +require 'puppet/parser/ast/hostclass' require 'puppet/parser/ast/ifstatement' require 'puppet/parser/ast/in_operator' require 'puppet/parser/ast/leaf' require 'puppet/parser/ast/match_operator' require 'puppet/parser/ast/minus' +require 'puppet/parser/ast/node' require 'puppet/parser/ast/nop' require 'puppet/parser/ast/not' +require 'puppet/parser/ast/relationship' require 'puppet/parser/ast/resource' require 'puppet/parser/ast/resource_defaults' +require 'puppet/parser/ast/resource_instance' require 'puppet/parser/ast/resource_override' require 'puppet/parser/ast/resource_reference' require 'puppet/parser/ast/resourceparam' require 'puppet/parser/ast/selector' require 'puppet/parser/ast/tag' require 'puppet/parser/ast/vardef' -require 'puppet/parser/ast/relationship' diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 529998e3c..7283a1f6c 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -16,25 +16,20 @@ class Puppet::Parser::AST # Evaluate our children. def evaluate(scope) - # Make a new array, so we don't have to deal with the details of - # flattening and such - items = [] - - # First clean out any AST::ASTArrays - @children.each { |child| - if child.instance_of?(AST::ASTArray) - child.each do |ac| - items << ac + result = [] + @children.each do |child| + # Skip things that respond to :instantiate (classes, nodes, + # and definitions), because they have already been + # instantiated. + if !child.respond_to?(:instantiate) + item = child.safeevaluate(scope) + if !item.nil? + # nil values are implicitly removed. + result.push(item) end - else - items << child end - } - - rets = items.flatten.collect { |child| - child.safeevaluate(scope) - } - rets.reject { |o| o.nil? } + end + result end def push(*ary) @@ -52,10 +47,4 @@ class Puppet::Parser::AST "[" + @children.collect { |c| c.to_s }.join(', ') + "]" end end - - # A simple container class, containing the parameters for an object. - # Used for abstracting the grammar declarations. Basically unnecessary - # except that I kept finding bugs because I had too many arrays that - # meant completely different things. - class ResourceInstance < ASTArray; end end diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb index 4e296e82f..db4c2b024 100644 --- a/lib/puppet/parser/ast/caseopt.rb +++ b/lib/puppet/parser/ast/caseopt.rb @@ -18,16 +18,12 @@ class Puppet::Parser::AST # Cache the @default value. return @default if defined?(@default) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - if subval.is_a?(AST::Default) - @default = true - break - end - } - else - @default = true if @value.is_a?(AST::Default) - end + @value.each { |subval| + if subval.is_a?(AST::Default) + @default = true + break + end + } @default ||= false @@ -36,23 +32,15 @@ class Puppet::Parser::AST # You can specify a list of values; return each in turn. def eachvalue(scope) - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval.safeevaluate(scope) - } - else - yield @value.safeevaluate(scope) - end + @value.each { |subval| + yield subval.safeevaluate(scope) + } end def eachopt - if @value.is_a?(AST::ASTArray) - @value.each { |subval| - yield subval - } - else - yield @value - end + @value.each { |subval| + yield subval + } end # Evaluate the actual statements; this only gets called if diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb index 09d5b4eb3..ef36b7143 100644 --- a/lib/puppet/parser/ast/collection.rb +++ b/lib/puppet/parser/ast/collection.rb @@ -5,61 +5,44 @@ require 'puppet/parser/collector' # An object that collects stored objects from the central cache and returns # them to the current host, yo. class Puppet::Parser::AST -class Collection < AST::Branch - attr_accessor :type, :query, :form - attr_reader :override - - associates_doc - - # We return an object that does a late-binding evaluation. - def evaluate(scope) - if self.query - str, code = self.query.safeevaluate scope - else - str = code = nil - end - - newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form) - - scope.compiler.add_collection(newcoll) - - # overrides if any - # Evaluate all of the specified params. - if @override - params = @override.collect do |param| - param.safeevaluate(scope) + class Collection < AST::Branch + attr_accessor :type, :query, :form + attr_reader :override + + associates_doc + + # We return an object that does a late-binding evaluation. + def evaluate(scope) + str, code = query && query.safeevaluate(scope) + + resource_type = scope.find_resource_type(@type) + newcoll = Puppet::Parser::Collector.new(scope, resource_type.name, str, code, self.form) + + scope.compiler.add_collection(newcoll) + + # overrides if any + # Evaluate all of the specified params. + if @override + params = @override.collect { |param| param.safeevaluate(scope) } + newcoll.add_override( + :parameters => params, + :file => @file, + :line => @line, + :source => scope.source, + :scope => scope + ) end - - newcoll.add_override( - - :parameters => params, - :file => @file, - :line => @line, - :source => scope.source, - - :scope => scope - ) + newcoll end - newcoll - end - - # Handle our parameter ourselves - def override=(override) - if override.is_a?(AST::ASTArray) - @override = override - else - - @override = AST::ASTArray.new( - - :line => override.line, - :file => override.file, - - :children => [override] - ) + # Handle our parameter ourselves + def override=(override) + @override = if override.is_a?(AST::ASTArray) + override + else + AST::ASTArray.new(:line => override.line,:file => override.file,:children => [override]) + end end end - -end end diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb new file mode 100644 index 000000000..c43422f82 --- /dev/null +++ b/lib/puppet/parser/ast/definition.rb @@ -0,0 +1,17 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Definition < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :context + + def initialize(name, context = {}, &ruby_code) + @name = name + @context = context + @ruby_code = ruby_code + end + + def instantiate(modname) + new_definition = Puppet::Resource::Type.new(:definition, @name, @context.merge(:module_name => modname)) + new_definition.ruby_code = @ruby_code if @ruby_code + [new_definition] + end +end diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb index 602016c75..80e6e6512 100644 --- a/lib/puppet/parser/ast/function.rb +++ b/lib/puppet/parser/ast/function.rb @@ -11,7 +11,6 @@ class Puppet::Parser::AST @settor = true def evaluate(scope) - # Make sure it's a defined function raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name) @@ -29,7 +28,7 @@ class Puppet::Parser::AST end # We don't need to evaluate the name, because it's plaintext - args = @arguments.safeevaluate(scope) + args = @arguments.safeevaluate(scope).map { |x| x == :undef ? '' : x } scope.send("function_#{@name}", args) end diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb new file mode 100644 index 000000000..cab5e4a24 --- /dev/null +++ b/lib/puppet/parser/ast/hostclass.rb @@ -0,0 +1,29 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Hostclass < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :name, :context + + def initialize(name, context = {}, &ruby_code) + @context = context + @name = name + @ruby_code = ruby_code + end + + def instantiate(modname) + new_class = Puppet::Resource::Type.new(:hostclass, @name, @context.merge(:module_name => modname)) + new_class.ruby_code = @ruby_code if @ruby_code + all_types = [new_class] + if code + code.each do |nested_ast_node| + if nested_ast_node.respond_to? :instantiate + all_types += nested_ast_node.instantiate(modname) + end + end + end + return all_types + end + + def code() + @context[:code] + end +end diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 49cde63ca..fcdd219d7 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -42,7 +42,7 @@ class Puppet::Parser::AST # The base string class. class String < AST::Leaf def evaluate(scope) - @value + @value.dup end def to_s @@ -148,12 +148,20 @@ class Puppet::Parser::AST key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key end + def array_index_or_key(object, key) + if object.is_a?(Array) + raise Puppet::ParserError, "#{key} is not an integer, but is used as an index of an array" unless key = Puppet::Parser::Scope.number?(key) + end + key + end + def evaluate(scope) object = evaluate_container(scope) + accesskey = evaluate_key(scope) raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array) - object[evaluate_key(scope)] + object[array_index_or_key(object, accesskey)] end # Assign value to this hashkey or array index @@ -166,7 +174,7 @@ class Puppet::Parser::AST end # assign to hash or array - object[accesskey] = value + object[array_index_or_key(object, accesskey)] = value end def to_s diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb new file mode 100644 index 000000000..b69a5c4e0 --- /dev/null +++ b/lib/puppet/parser/ast/node.rb @@ -0,0 +1,20 @@ +require 'puppet/parser/ast/top_level_construct' + +class Puppet::Parser::AST::Node < Puppet::Parser::AST::TopLevelConstruct + attr_accessor :names, :context + + def initialize(names, context = {}, &ruby_code) + raise ArgumentError, "names should be an array" unless names.is_a? Array + @names = names + @context = context + @ruby_code = ruby_code + end + + def instantiate(modname) + @names.collect do |name| + new_node = Puppet::Resource::Type.new(:node, name, @context.merge(:module_name => modname)) + new_node.ruby_code = @ruby_code if @ruby_code + new_node + end + end +end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 1b063c984..ce3c499c5 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -3,26 +3,15 @@ require 'puppet/parser/ast/resource_reference' # Any normal puppet resource declaration. Can point to a definition or a # builtin type. class Puppet::Parser::AST -class Resource < AST::ResourceReference +class Resource < AST::Branch associates_doc - attr_accessor :title, :type, :exported, :virtual - attr_reader :parameters + attr_accessor :type, :instances, :exported, :virtual # Does not actually return an object; instead sets an object # in the current scope. def evaluate(scope) - # Evaluate all of the specified params. - paramobjects = parameters.collect { |param| - param.safeevaluate(scope) - } - - resource_titles = @title.safeevaluate(scope) - - # it's easier to always use an array, even for only one name - resource_titles = [resource_titles] unless resource_titles.is_a?(Array) - # We want virtual to be true if exported is true. We can't # just set :virtual => self.virtual in the initialization, # because sometimes the :virtual attribute is set *after* @@ -30,48 +19,49 @@ class Resource < AST::ResourceReference # is true. Argh, this was a very tough one to track down. virt = self.virtual || self.exported - # This is where our implicit iteration takes place; if someone - # passed an array as the name, then we act just like the called us - # many times. - resource_titles.flatten.collect { |resource_title| - exceptwrap :type => Puppet::ParseError do + # First level of implicit iteration: build a resource for each + # instance. This handles things like: + # file { '/foo': owner => blah; '/bar': owner => blah } + @instances.collect { |instance| - resource = Puppet::Parser::Resource.new( - type, resource_title, - :parameters => paramobjects, - :file => self.file, - :line => self.line, - :exported => self.exported, - :virtual => virt, - :source => scope.source, - :scope => scope, - - :strict => true - ) + # Evaluate all of the specified params. + paramobjects = instance.parameters.collect { |param| + param.safeevaluate(scope) + } - # And then store the resource in the compiler. - # At some point, we need to switch all of this to return - # resources instead of storing them like this. - scope.compiler.add_resource(scope, resource) - resource - end - }.reject { |resource| resource.nil? } - end + resource_titles = instance.title.safeevaluate(scope) + + # it's easier to always use an array, even for only one name + resource_titles = [resource_titles] unless resource_titles.is_a?(Array) + + fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles) - # Set the parameters for our object. - def parameters=(params) - if params.is_a?(AST::ASTArray) - @parameters = params - else + # Second level of implicit iteration; build a resource for each + # title. This handles things like: + # file { ['/foo', '/bar']: owner => blah } + resource_titles.flatten.collect { |resource_title| + exceptwrap :type => Puppet::ParseError do + resource = Puppet::Parser::Resource.new( + fully_qualified_type, resource_title, + :parameters => paramobjects, + :file => self.file, + :line => self.line, + :exported => self.exported, + :virtual => virt, + :source => scope.source, + :scope => scope, + :strict => true + ) - @parameters = AST::ASTArray.new( - - :line => params.line, - :file => params.file, - - :children => [params] - ) - end + if resource.resource_type.is_a? Puppet::Resource::Type + resource.resource_type.instantiate_resource(scope, resource) + end + scope.compiler.add_resource(scope, resource) + scope.compiler.evaluate_classes([resource_title],scope,false) if fully_qualified_type == 'class' + resource + end + } + }.flatten.reject { |resource| resource.nil? } end end end diff --git a/lib/puppet/parser/ast/resource_instance.rb b/lib/puppet/parser/ast/resource_instance.rb new file mode 100644 index 000000000..ebfb17bf1 --- /dev/null +++ b/lib/puppet/parser/ast/resource_instance.rb @@ -0,0 +1,9 @@ +require 'puppet/parser/ast/branch' + +class Puppet::Parser::AST + class ResourceInstance < Branch + # A simple container for a parameter for an object. Consists of a + # title and a set of parameters. + attr_accessor :title, :parameters + end +end diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb index e0be889ff..d638202ab 100644 --- a/lib/puppet/parser/ast/resource_override.rb +++ b/lib/puppet/parser/ast/resource_override.rb @@ -3,12 +3,11 @@ require 'puppet/parser/ast/resource' class Puppet::Parser::AST # Set a parameter on a resource specification created somewhere else in the # configuration. The object is responsible for verifying that this is allowed. - class ResourceOverride < Resource + class ResourceOverride < AST::Branch associates_doc - attr_accessor :object - attr_reader :parameters + attr_accessor :object, :parameters # Iterate across all of our children. def each diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb index 5d8334335..0f8e655bf 100644 --- a/lib/puppet/parser/ast/resource_reference.rb +++ b/lib/puppet/parser/ast/resource_reference.rb @@ -7,8 +7,15 @@ class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch # Evaluate our object, but just return a simple array of the type # and name. def evaluate(scope) - titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) } - return(titles.length == 1 ? titles.pop : titles) + titles = Array(title.safeevaluate(scope)) + + a_type, titles = scope.resolve_type_and_titles(type, titles) + + resources = titles.collect{ |a_title| + Puppet::Resource.new(a_type, a_title) + } + + return(resources.length == 1 ? resources.pop : resources) end def to_s diff --git a/lib/puppet/parser/ast/top_level_construct.rb b/lib/puppet/parser/ast/top_level_construct.rb new file mode 100644 index 000000000..901a939c2 --- /dev/null +++ b/lib/puppet/parser/ast/top_level_construct.rb @@ -0,0 +1,4 @@ +# The base class for AST nodes representing top level things: +# hostclasses, definitions, and nodes. +class Puppet::Parser::AST::TopLevelConstruct < Puppet::Parser::AST +end diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index a901c0dd6..c60e1d4fb 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -19,7 +19,12 @@ class Puppet::Parser::Compiler rescue => detail puts detail.backtrace if Puppet[:trace] raise Puppet::Error, "#{detail} on node #{node.name}" - end + ensure + # We get these from the environment and only cache them in a thread + # variable for the duration of the compilation. + Thread.current[:known_resource_types] = nil + Thread.current[:env_module_directories] = nil + end attr_reader :node, :facts, :collections, :catalog, :node_scope, :resources, :relationships @@ -51,13 +56,10 @@ class Puppet::Parser::Compiler # Note that this will fail if the resource is not unique. @catalog.add_resource(resource) - set_container_resource(scope, resource) - end - # Add our container edge. If we're a class, then we get treated specially - we can - # control the stage that the class is applied in. Otherwise, we just - # get added to our parent container. - def set_container_resource(scope, resource) + # Add our container edge. If we're a class, then we get treated specially - we can + # control the stage that the class is applied in. Otherwise, we just + # get added to our parent container. return if resource.type.to_s.downcase == "stage" if resource.type.to_s.downcase != "class" @@ -65,15 +67,14 @@ class Puppet::Parser::Compiler return @catalog.add_edge(scope.resource, resource) end - unless stage = @catalog.resource(:stage, resource[:stage] || :main) + unless stage = @catalog.resource(:stage, resource[:stage] || (scope && scope.resource && scope.resource[:stage]) || :main) raise ArgumentError, "Could not find stage #{resource[:stage] || :main} specified by #{resource}" end + resource[:stage] ||= stage.title unless stage.title == :main @catalog.add_edge(stage, resource) end - private :set_container_resource - # Do we use nodes found in the code, vs. the external node sources? def ast_nodes? known_resource_types.nodes? @@ -143,7 +144,7 @@ class Puppet::Parser::Compiler if klass = scope.find_hostclass(name) found << name and next if scope.class_scope(klass) - resource = klass.mk_plain_resource(scope) + resource = klass.ensure_in_catalog(scope) # If they've disabled lazy evaluation (which the :include function does), # then evaluate our resource immediately. @@ -219,7 +220,7 @@ class Puppet::Parser::Compiler # Create a resource to model this node, and then add it to the list # of resources. - resource = astnode.mk_plain_resource(topscope) + resource = astnode.ensure_in_catalog(topscope) resource.evaluate @@ -284,10 +285,7 @@ class Puppet::Parser::Compiler @main_resource = Puppet::Parser::Resource.new("class", :main, :scope => @topscope, :source => @main) @topscope.resource = @main_resource - @resources << @main_resource - @catalog.add_resource(@main_resource) - - set_container_resource(@topscope, @main_resource) + add_resource(@topscope, @main_resource) @main_resource.evaluate end diff --git a/lib/puppet/parser/files.rb b/lib/puppet/parser/files.rb index 9ef05e102..f34683153 100644 --- a/lib/puppet/parser/files.rb +++ b/lib/puppet/parser/files.rb @@ -24,7 +24,7 @@ module Puppet::Parser::Files # Than that would be a "no." end abspat = File::expand_path(start, cwd) - [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{,.pp,.rb}' : '' )).uniq.reject { |f| FileTest.directory?(f) }] + [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{.pp,.rb}' : '' )).uniq.reject { |f| FileTest.directory?(f) }] end # Find the concrete file denoted by +file+. If +file+ is absolute, diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index c238da5d4..5807c0bbe 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -20,7 +20,7 @@ module Puppet::Parser::Functions @autoloader = Puppet::Util::Autoload.new( self, "puppet/parser/functions", - + :wrap => false ) end @@ -73,8 +73,10 @@ module Puppet::Parser::Functions def self.function(name) name = symbolize(name) - unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name) - autoloader.load(name,Environment.current || Environment.root) + @functions.synchronize do + unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name) + autoloader.load(name,Environment.current || Environment.root) + end end ( functions(Environment.root)[name] || functions[name] || {:name => false} )[:name] @@ -94,7 +96,7 @@ module Puppet::Parser::Functions ret += "Undocumented.\n" end - ret += "\n\n- **Type**: #{hash[:type]}\n\n" + ret += "\n\n- *Type*: #{hash[:type]}\n\n" end ret diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb index 2930a65cc..90632af2f 100644 --- a/lib/puppet/parser/functions/defined.rb +++ b/lib/puppet/parser/functions/defined.rb @@ -3,7 +3,7 @@ Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Dete type is defined, either as a native type or a defined type, or whether a class is defined. This is useful for checking whether a class is defined and only including it if it is. This function can also test whether a resource has been defined, using resource references - (e.g., ``if defined(File['/tmp/myfile']) { ... }``). This function is unfortunately + (e.g., `if defined(File['/tmp/myfile']) { ... }`). This function is unfortunately dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals| result = false vals = [vals] unless vals.is_a?(Array) diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb new file mode 100644 index 000000000..bc55410b9 --- /dev/null +++ b/lib/puppet/parser/functions/extlookup.rb @@ -0,0 +1,157 @@ +require 'csv' + +module Puppet::Parser::Functions + newfunction(:extlookup, + :type => :rvalue, + :doc => "This is a parser function to read data from external files, this version +uses CSV files but the concept can easily be adjust for databases, yaml +or any other queryable data source. + +The object of this is to make it obvious when it's being used, rather than +magically loading data in when an module is loaded I prefer to look at the code +and see statements like: + + $snmp_contact = extlookup(\"snmp_contact\") + +The above snippet will load the snmp_contact value from CSV files, this in its +own is useful but a common construct in puppet manifests is something like this: + + case $domain { + \"myclient.com\": { $snmp_contact = \"John Doe <john@myclient.com>\" } + default: { $snmp_contact = \"My Support <support@my.com>\" } + } + +Over time there will be a lot of this kind of thing spread all over your manifests +and adding an additional client involves grepping through manifests to find all the +places where you have constructs like this. + +This is a data problem and shouldn't be handled in code, a using this function you +can do just that. + +First you configure it in site.pp: + + $extlookup_datadir = \"/etc/puppet/manifests/extdata\" + $extlookup_precedence = [\"%{fqdn}\", \"domain_%{domain}\", \"common\"] + +The array tells the code how to resolve values, first it will try to find it in +web1.myclient.com.csv then in domain_myclient.com.csv and finally in common.csv + +Now create the following data files in /etc/puppet/manifests/extdata: + + domain_myclient.com.csv: + snmp_contact,John Doe <john@myclient.com> + root_contact,support@%{domain} + client_trusted_ips,192.168.1.130,192.168.10.0/24 + + common.csv: + snmp_contact,My Support <support@my.com> + root_contact,support@my.com + +Now you can replace the case statement with the simple single line to achieve +the exact same outcome: + + $snmp_contact = extlookup(\"snmp_contact\") + +The above code shows some other features, you can use any fact or variable that +is in scope by simply using %{varname} in your data files, you can return arrays +by just having multiple values in the csv after the initial variable name. + +In the event that a variable is nowhere to be found a critical error will be raised +that will prevent your manifest from compiling, this is to avoid accidentally putting +in empty values etc. You can however specify a default value: + + $ntp_servers = extlookup(\"ntp_servers\", \"1.${country}.pool.ntp.org\") + +In this case it will default to \"1.${country}.pool.ntp.org\" if nothing is defined in +any data file. + +You can also specify an additional data file to search first before any others at use +time, for example: + + $version = extlookup(\"rsyslog_version\", \"present\", \"packages\") + package{\"rsyslog\": ensure => $version } + +This will look for a version configured in packages.csv and then in the rest as configured +by $extlookup_precedence if it's not found anywhere it will default to `present`, this kind +of use case makes puppet a lot nicer for managing large amounts of packages since you do not +need to edit a load of manifests to do simple things like adjust a desired version number. + +Precedence values can have variables embedded in them in the form %{fqdn}, you could for example do: + + $extlookup_precedence = [\"hosts/%{fqdn}\", \"common\"] + +This will result in /path/to/extdata/hosts/your.box.com.csv being searched. + +This is for back compatibility to interpolate variables with %. % interpolation is a workaround for a problem that has been fixed: Puppet variable interpolation at top scope used to only happen on each run.") do |args| + + key = args[0] + + default = args[1] + datafile = args[2] + + raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3 + + extlookup_datadir = lookupvar('extlookup_datadir') + extlookup_precedence = Array.new + + extlookup_precedence = lookupvar('extlookup_precedence').collect do |var| + var.gsub(/%\{(.+?)\}/) do |capture| + lookupvar($1) + end + end + + datafiles = Array.new + + # if we got a custom data file, put it first in the array of search files + if datafile != "" + datafiles << extlookup_datadir + "/#{datafile}.csv" if File.exists?(extlookup_datadir + "/#{datafile}.csv") + end + + extlookup_precedence.each do |d| + datafiles << extlookup_datadir + "/#{d}.csv" + end + + desired = nil + + datafiles.each do |file| + if desired.nil? + if File.exists?(file) + result = CSV.read(file).find_all do |r| + r[0] == key + end + + # return just the single result if theres just one, + # else take all the fields in the csv and build an array + if result.length > 0 + if result[0].length == 2 + val = result[0][1].to_s + + # parse %{}'s in the CSV into local variables using lookupvar() + while val =~ /%\{(.+?)\}/ + val.gsub!(/%\{#{$1}\}/, lookupvar($1)) + end + + desired = val + elsif result[0].length > 1 + length = result[0].length + cells = result[0][1,length] + + # Individual cells in a CSV result are a weird data type and throws + # puppets yaml parsing, so just map it all to plain old strings + desired = cells.map do |c| + # parse %{}'s in the CSV into local variables using lookupvar() + while c =~ /%\{(.+?)\}/ + c.gsub!(/%\{#{$1}\}/, lookupvar($1)) + end + + c.to_s + end + end + end + end + end + end + + desired || default or raise Puppet::ParseError, "No match found for '#{key}' in any data file during extlookup()" + end +end diff --git a/lib/puppet/parser/functions/file.rb b/lib/puppet/parser/functions/file.rb index 963111260..19ab9ba2e 100644 --- a/lib/puppet/parser/functions/file.rb +++ b/lib/puppet/parser/functions/file.rb @@ -2,7 +2,7 @@ Puppet::Parser::Functions::newfunction( :file, :type => :rvalue, - + :doc => "Return the contents of a file. Multiple files can be passed, and the first file that exists will be read in.") do |vals| ret = nil diff --git a/lib/puppet/parser/functions/inline_template.rb b/lib/puppet/parser/functions/inline_template.rb index 46e000383..9759ff6e1 100644 --- a/lib/puppet/parser/functions/inline_template.rb +++ b/lib/puppet/parser/functions/inline_template.rb @@ -1,9 +1,10 @@ Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :doc => - "Evaluate a template string and return its value. See `the templating docs - <http://docs.puppetlabs.com/guides/templating.html>`_ for more information. Note that - if multiple template strings are specified, their output is all concatenated - and returned as the output of the function.") do |vals| - require 'erb' + "Evaluate a template string and return its value. See + [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for + more information. Note that if multiple template strings are specified, their + output is all concatenated and returned as the output of the function.") do |vals| + + require 'erb' vals.collect do |string| # Use a wrapper, so the template can't get access to the full diff --git a/lib/puppet/parser/functions/md5.rb b/lib/puppet/parser/functions/md5.rb new file mode 100644 index 000000000..f7a4f7222 --- /dev/null +++ b/lib/puppet/parser/functions/md5.rb @@ -0,0 +1,5 @@ +Puppet::Parser::Functions::newfunction(:md5, :type => :rvalue, :doc => "Returns a MD5 hash value from a provided string.") do |args| + require 'md5' + + Digest::MD5.hexdigest(args[0]) +end diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb index 4247b8af8..c21ccd14a 100644 --- a/lib/puppet/parser/functions/realize.rb +++ b/lib/puppet/parser/functions/realize.rb @@ -5,7 +5,7 @@ Puppet::Parser::Functions::newfunction(:realize, :doc => "Make a virtual object when you want to know the name of the virtual object and don't want to bother with a full collection. It is slightly faster than a collection, and, of course, is a bit shorter. You must pass the object using a - reference; e.g.: ``realize User[luke]``." ) do |vals| + reference; e.g.: `realize User[luke]`." ) do |vals| coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual) vals = [vals] unless vals.is_a?(Array) coll.resources = vals.flatten diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb index c0aeef222..f655db7b3 100644 --- a/lib/puppet/parser/functions/regsubst.rb +++ b/lib/puppet/parser/functions/regsubst.rb @@ -6,37 +6,37 @@ module Puppet::Parser::Functions :doc => " Perform regexp replacement on a string or array of strings. -- **Parameters** (in order): +* *Parameters* (in order): -:target: The string or array of strings to operate on. If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array. + _target_ The string or array of strings to operate on. If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array. -:regexp: The regular expression matching the target string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself. + _regexp_ The regular expression matching the target string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself. -:replacement: Replacement string. Can contain back references to what was matched using \\0, \\1, and so on. + _replacement_ Replacement string. Can contain back references to what was matched using \\0, \\1, and so on. -:flags: Optional. String of single letter flags for how the regexp is interpreted: + _flags_ Optional. String of single letter flags for how the regexp is interpreted: - - **E** Extended regexps - - **I** Ignore case in regexps - - **M** Multiline regexps - - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced. + - *E* Extended regexps + - *I* Ignore case in regexps + - *M* Multiline regexps + - *G* Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced. -:lang: Optional. How to handle multibyte characters. A single-character string with the following values: + _lang_ Optional. How to handle multibyte characters. A single-character string with the following values: - - **N** None - - **E** EUC - - **S** SJIS - - **U** UTF-8 + - *N* None + - *E* EUC + - *S* SJIS + - *U* UTF-8 -- **Examples** +* *Examples* -Get the third octet from the node's IP address:: +Get the third octet from the node's IP address: - $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3') + $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3') -Put angle brackets around each octet in the node's IP address:: +Put angle brackets around each octet in the node's IP address: - $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G') + $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G') ") \ do |args| unless args.length.between?(3, 5) diff --git a/lib/puppet/parser/functions/require.rb b/lib/puppet/parser/functions/require.rb index 3f98c9523..64285307e 100644 --- a/lib/puppet/parser/functions/require.rb +++ b/lib/puppet/parser/functions/require.rb @@ -12,9 +12,8 @@ relationships between classes. This function is a superset of the class depends on the required class. Warning: using require in place of include can lead to unwanted dependency cycles. - For instance the following manifest, with 'require' instead of 'include' - would produce a nasty dependence cycle, because notify imposes a before - between File[/foo] and Service[foo]:: + +For instance the following manifest, with 'require' instead of 'include' would produce a nasty dependence cycle, because notify imposes a before between File[/foo] and Service[foo]: class myservice { service { foo: ensure => running } diff --git a/lib/puppet/parser/functions/split.rb b/lib/puppet/parser/functions/split.rb index 5d0a9dabc..52394095a 100644 --- a/lib/puppet/parser/functions/split.rb +++ b/lib/puppet/parser/functions/split.rb @@ -6,7 +6,7 @@ module Puppet::Parser::Functions :doc => "\ Split a string variable into an array using the specified split regexp. - Usage:: + Usage: $string = 'v1.v2:v3.v4' $array_var1 = split($string, ':') diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb index 5ada0fed7..5eb4a4f9d 100644 --- a/lib/puppet/parser/functions/sprintf.rb +++ b/lib/puppet/parser/functions/sprintf.rb @@ -5,7 +5,7 @@ module Puppet::Parser::Functions :doc => "Perform printf-style formatting of text. - The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the ``Kernel::sprintf`` function in Ruby for all the details.") do |args| + The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the `Kernel::sprintf` function in Ruby for all the details.") do |args| raise Puppet::ParseError, 'sprintf() needs at least one argument' if args.length < 1 fmt = args.shift return sprintf(fmt, *args) diff --git a/lib/puppet/parser/functions/template.rb b/lib/puppet/parser/functions/template.rb index f51bcc1e2..6fa110332 100644 --- a/lib/puppet/parser/functions/template.rb +++ b/lib/puppet/parser/functions/template.rb @@ -1,6 +1,8 @@ Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :doc => - "Evaluate a template and return its value. See `the templating docs - <http://docs.puppetlabs.com/guides/templating.html>`_ for more information. + "Evaluate a template and return its value. See + [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for + more information. + Note that if multiple templates are specified, their output is all concatenated and returned as the output of the function.") do |vals| require 'erb' diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index b38406532..6091e0923 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -3,26 +3,26 @@ require 'puppet/util/package' Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, - + :doc => "Compares two versions -Prototype:: +Prototype: - \$result = versioncmp(a, b) + \$result = versioncmp(a, b) - where a and b are arbitrary version strings +Where a and b are arbitrary version strings -This functions returns a number:: +This functions returns a number: - * > 0 if version a is greater than version b - * == 0 if both version are equals - * < 0 if version a is less than version b +* Greater than 0 if version a is greater than version b +* Equal to 0 if both version are equals +* Less than 0 if version a is less than version b -Example:: +Example: - if versioncmp('2.6-1', '2.4.5') > 0 { - notice('2.6-1 is > than 2.4.5') - } + if versioncmp('2.6-1', '2.4.5') > 0 { + notice('2.6-1 is > than 2.4.5') + } ") do |args| diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra index 7a316d4d7..ecb27f363 100644 --- a/lib/puppet/parser/grammar.ra +++ b/lib/puppet/parser/grammar.ra @@ -28,41 +28,33 @@ prechigh preclow rule -program: statements { - if val[0] - # Make sure we always return an array. - if val[0].is_a?(AST::ASTArray) - if val[0].children.empty? - result = nil - else - result = val[0] - end - else - result = aryfy(val[0]) - end - else - result = nil - end -} +program: statements_and_declarations | nil -statements: statement - | statements statement { - if val[0] and val[1] - if val[0].instance_of?(AST::ASTArray) + statements_and_declarations: statement_or_declaration { + result = ast AST::ASTArray, :children => (val[0] ? [val[0]] : []) + } + | statements_and_declarations statement_or_declaration { + if val[1] val[0].push(val[1]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[1]] end - elsif obj = (val[0] || val[1]) - result = obj - else result = nil + result = val[0] + } + +# statements is like statements_and_declarations, but it doesn't allow +# nested definitions, classes, or nodes. +statements: statements_and_declarations { + val[0].each do |stmt| + if stmt.is_a?(AST::TopLevelConstruct) + error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \ + :line => stmt.context[:line], :file => stmt.context[:file] + end end + result = val[0] } # The main list of valid statements -statement: resource +statement_or_declaration: resource | virtualresource | collection | assignment @@ -89,19 +81,17 @@ relationship_side: resource | resourceref | collection edge: IN_EDGE | OUT_EDGE | IN_EDGE_SUB | OUT_EDGE_SUB fstatement: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement } | NAME LPAREN funcvalues COMMA RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :statement } | NAME LPAREN RPAREN { result = ast AST::Function, @@ -111,29 +101,22 @@ fstatement: NAME LPAREN funcvalues RPAREN { :ftype => :statement } | NAME funcvalues { - args = aryfy(val[1]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[1], :ftype => :statement } -funcvalues: namestring - | resourceref +funcvalues: namestring { result = aryfy(val[0]) } + | resourceref { result = aryfy(val[0]) } | funcvalues COMMA namestring { - result = aryfy(val[0], val[2]) - result.line = @lexer.line - result.file = @lexer.file + val[0].push(val[2]) + result = val[0] } | funcvalues COMMA resourceref { - unless val[0].is_a?(AST::ASTArray) - val[0] = aryfy(val[0]) - end - - val[0].push(val[2]) - - result = val[0] + val[0].push(val[2]) + result = val[0] } # This is *almost* an rvalue, but I couldn't get a full @@ -152,23 +135,7 @@ namestring: name resource: classname LBRACE resourceinstances endsemi RBRACE { @lexer.commentpop - array = val[2] - array = [array] if array.instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray - - # this iterates across each specified resourceinstance - array.each { |instance| - raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance) - # now, i need to somehow differentiate between those things with - # arrays in their names, and normal things - - result.push ast( - AST::Resource, - :type => val[0], - :title => instance[0], - - :parameters => instance[1]) - } + result = ast(AST::Resource, :type => val[0], :instances => val[2]) } | classname LBRACE params endcomma RBRACE { # This is a deprecated syntax. error "All resource specifications require names" @@ -197,14 +164,8 @@ virtualresource: at resource { method = type.to_s + "=" - # Just mark our resources as exported and pass them through. - if val[1].instance_of?(AST::ASTArray) - val[1].each do |obj| - obj.send(method, true) - end - else - val[1].send(method, true) - end + # Just mark our resource as exported and pass it through. + val[1].send(method, true) result = val[1] } @@ -303,17 +264,13 @@ colllval: variable | name resourceinst: resourcename COLON params endcomma { - result = ast AST::ResourceInstance, :children => [val[0],val[2]] + result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] } -resourceinstances: resourceinst +resourceinstances: resourceinst { result = aryfy(val[0]) } | resourceinstances SEMIC resourceinst { - if val[0].instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray, :children => [val[0],val[2]] - else val[0].push val[2] result = val[0] - end } endsemi: # nothing @@ -358,14 +315,10 @@ params: # nothing { result = ast AST::ASTArray } - | param { result = val[0] } + | param { result = aryfy(val[0]) } | params COMMA param { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } param: NAME FARROW rvalue { @@ -384,24 +337,14 @@ anyparams: # nothing { result = ast AST::ASTArray } - | anyparam { result = val[0] } + | anyparam { result = aryfy(val[0]) } | anyparams COMMA anyparam { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } -rvalues: rvalue - | rvalues comma rvalue { - if val[0].instance_of?(AST::ASTArray) - result = val[0].push(val[2]) - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end -} +rvalues: rvalue { result = aryfy(val[0]) } + | rvalues comma rvalue { result = val[0].push(val[2]) } simplervalue: quotedtext | name @@ -425,10 +368,9 @@ rvalue: quotedtext # We currently require arguments in these functions. funcrvalue: NAME LPAREN funcvalues RPAREN { - args = aryfy(val[2]) result = ast AST::Function, :name => val[0][:value], :line => val[0][:line], - :arguments => args, + :arguments => val[2], :ftype => :rvalue } | NAME LPAREN RPAREN { result = ast AST::Function, @@ -572,19 +514,13 @@ expression: rvalue casestatement: CASE rvalue LBRACE caseopts RBRACE { @lexer.commentpop - options = val[3] - options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray) - result = ast AST::CaseStatement, :test => val[1], :options => options + result = ast AST::CaseStatement, :test => val[1], :options => val[3] } -caseopts: caseopt +caseopts: caseopt { result = aryfy(val[0]) } | caseopts caseopt { - if val[0].instance_of?(AST::ASTArray) val[0].push val[1] result = val[0] - else - result = ast AST::ASTArray, :children => [val[0], val[1]] - end } caseopt: casevalues COLON LBRACE statements RBRACE { @@ -601,14 +537,10 @@ caseopt: casevalues COLON LBRACE statements RBRACE { ) } -casevalues: selectlhand +casevalues: selectlhand { result = aryfy(val[0]) } | casevalues COMMA selectlhand { - if val[0].instance_of?(AST::ASTArray) val[0].push(val[2]) result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end } selector: selectlhand QMARK svalues { @@ -657,48 +589,51 @@ import: IMPORT strings { import(file) end - result = AST::ASTArray.new(:children => []) + result = nil } # Disable definition inheritance for now. 8/27/06, luke #definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE { definition: DEFINE classname argumentlist LBRACE statements RBRACE { @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line] + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :code => val[4], + :line => val[0][:line])) @lexer.indefine = false - result = nil #} | DEFINE NAME argumentlist parent LBRACE RBRACE { } | DEFINE classname argumentlist LBRACE RBRACE { @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line] + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) @lexer.indefine = false - result = nil } #hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE { -hostclass: CLASS classname argumentlist classparent LBRACE statements RBRACE { +hostclass: CLASS classname argumentlist classparent LBRACE statements_and_declarations RBRACE { @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :code => val[5], :line => val[0][:line])) } | CLASS classname argumentlist classparent LBRACE RBRACE { @lexer.commentpop # Our class gets defined in the parent namespace, not our own. @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :line => val[0][:line])) } nodedef: NODE hostnames nodeparent LBRACE statements RBRACE { @lexer.commentpop - newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Node.new(val[1], + ast_context(true).merge(:parent => val[2], :code => val[4], + :line => val[0][:line])) } | NODE hostnames nodeparent LBRACE RBRACE { @lexer.commentpop - newnode val[1], :parent => val[2], :line => val[0][:line] - result = nil + result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) } classref: CLASSREF { result = val[0][:value] } @@ -709,10 +644,11 @@ classname: NAME { result = val[0][:value] } # Multiple hostnames, as used for node names. These are all literal # strings, not AST objects. -hostnames: nodename +hostnames: nodename { + result = [result] +} | hostnames COMMA nodename { result = val[0] - result = [result] unless result.is_a?(Array) result << val[2] } @@ -778,22 +714,9 @@ variable: VARIABLE { result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] } -array: LBRACK rvalues RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end -} - | LBRACK rvalues COMMA RBRACK { - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end -} | LBRACK RBRACK { - result = ast AST::ASTArray -} +array: LBRACK rvalues RBRACK { result = val[1] } + | LBRACK rvalues COMMA RBRACK { result = val[1] } + | LBRACK RBRACK { result = ast AST::ASTArray } comma: FARROW | COMMA diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb index 1e10ff96c..31d39ae2f 100644 --- a/lib/puppet/parser/lexer.rb +++ b/lib/puppet/parser/lexer.rb @@ -221,7 +221,7 @@ class Puppet::Parser::Lexer TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true TOKENS.add_token :SQUOTE, "'" do |lexer, value| - [TOKENS[:STRING], lexer.slurpstring(value).first ] + [TOKENS[:STRING], lexer.slurpstring(value,["'"],:ignore_invalid_escapes).first ] end DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING} @@ -483,7 +483,7 @@ class Puppet::Parser::Lexer yield [final_token.name, token_value] if @previous_token - namestack(value) if @previous_token.name == :CLASS + namestack(value) if @previous_token.name == :CLASS and value != '{' if @previous_token.name == :DEFINE if indefine? @@ -517,24 +517,24 @@ class Puppet::Parser::Lexer # we've encountered the start of a string... # slurp in the rest of the string and return it - Valid_escapes_in_strings = %w{ \\ $ ' " n t s }+["\n"] - def slurpstring(terminators) + def slurpstring(terminators,escapes=%w{ \\ $ ' " n t s }+["\n"],ignore_invalid_escapes=false) # we search for the next quote that isn't preceded by a # backslash; the caret is there to match empty strings - str = @scanner.scan_until(/([^\\]|^)[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'" + str = @scanner.scan_until(/([^\\]|^|[^\\])([\\]{2})*[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'" @line += str.count("\n") # literal carriage returns add to the line count. - str.gsub!(/\\(.)/) { - case ch=$1 - when 'n'; "\n" - when 't'; "\t" - when 's'; " " - else - if Valid_escapes_in_strings.include? ch and not (ch == '"' and terminators == "'") - ch - else - Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" - "\\#{ch}" + str.gsub!(/\\(.)/m) { + ch = $1 + if escapes.include? ch + case ch + when 'n'; "\n" + when 't'; "\t" + when 's'; " " + when "\n": '' + else ch end + else + Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}" unless ignore_invalid_escapes + "\\#{ch}" end } [ str[0..-2],str[-1,1] ] diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb index 5be9e5a3f..60b272e76 100644 --- a/lib/puppet/parser/parser.rb +++ b/lib/puppet/parser/parser.rb @@ -13,9 +13,9 @@ require 'puppet/parser/lexer' require 'puppet/parser/ast' module Puppet - class ParseError < Puppet::Error; end - class ImportError < Racc::ParseError; end - class AlreadyImportedError < ImportError; end + class ParseError < Puppet::Error; end + class ImportError < Racc::ParseError; end + class AlreadyImportedError < ImportError; end end @@ -25,7 +25,7 @@ module Puppet class Parser < Racc::Parser -module_eval <<'..end grammar.ra modeval..id7145220b1b', 'grammar.ra', 876 +module_eval <<'..end grammar.ra modeval..id6362f948d9', 'grammar.ra', 788 # It got too annoying having code in a file that needs to be compiled. require 'puppet/parser/parser_support' @@ -37,16 +37,17 @@ require 'puppet/parser/parser_support' # $Id$ -..end grammar.ra modeval..id7145220b1b +..end grammar.ra modeval..id6362f948d9 ##### racc 1.4.5 generates ### racc_reduce_table = [ 0, 0, :racc_error, - 1, 70, :_reduce_1, 1, 70, :_reduce_none, - 1, 71, :_reduce_none, + 1, 70, :_reduce_none, + 1, 71, :_reduce_3, 2, 71, :_reduce_4, + 1, 74, :_reduce_5, 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, @@ -61,864 +62,820 @@ racc_reduce_table = [ 1, 73, :_reduce_none, 1, 73, :_reduce_none, 1, 73, :_reduce_none, - 3, 87, :_reduce_19, - 3, 87, :_reduce_20, - 1, 88, :_reduce_none, - 1, 88, :_reduce_none, - 1, 88, :_reduce_none, - 1, 89, :_reduce_none, + 3, 88, :_reduce_20, + 3, 88, :_reduce_21, 1, 89, :_reduce_none, 1, 89, :_reduce_none, 1, 89, :_reduce_none, - 4, 81, :_reduce_28, - 5, 81, :_reduce_29, - 3, 81, :_reduce_30, - 2, 81, :_reduce_31, - 1, 91, :_reduce_none, - 1, 91, :_reduce_none, - 3, 91, :_reduce_34, - 3, 91, :_reduce_35, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_none, - 1, 92, :_reduce_44, - 5, 74, :_reduce_45, - 5, 74, :_reduce_46, - 5, 74, :_reduce_47, - 5, 85, :_reduce_48, - 2, 75, :_reduce_49, - 1, 108, :_reduce_50, - 2, 108, :_reduce_51, - 6, 76, :_reduce_52, - 2, 76, :_reduce_53, - 3, 109, :_reduce_54, - 3, 109, :_reduce_55, - 1, 110, :_reduce_none, - 1, 110, :_reduce_none, - 3, 110, :_reduce_58, + 1, 90, :_reduce_none, + 1, 90, :_reduce_none, + 1, 90, :_reduce_none, + 1, 90, :_reduce_none, + 4, 82, :_reduce_29, + 5, 82, :_reduce_30, + 3, 82, :_reduce_31, + 2, 82, :_reduce_32, + 1, 92, :_reduce_33, + 1, 92, :_reduce_34, + 3, 92, :_reduce_35, + 3, 92, :_reduce_36, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_none, + 1, 93, :_reduce_45, + 5, 75, :_reduce_46, + 5, 75, :_reduce_47, + 5, 75, :_reduce_48, + 5, 86, :_reduce_49, + 2, 76, :_reduce_50, + 1, 109, :_reduce_51, + 2, 109, :_reduce_52, + 6, 77, :_reduce_53, + 2, 77, :_reduce_54, + 3, 110, :_reduce_55, + 3, 110, :_reduce_56, 1, 111, :_reduce_none, - 3, 111, :_reduce_60, - 1, 112, :_reduce_61, - 1, 112, :_reduce_62, - 3, 113, :_reduce_63, - 3, 113, :_reduce_64, - 1, 114, :_reduce_none, - 1, 114, :_reduce_none, - 4, 116, :_reduce_67, - 1, 102, :_reduce_none, - 3, 102, :_reduce_69, - 0, 103, :_reduce_none, - 1, 103, :_reduce_none, - 1, 118, :_reduce_72, - 1, 93, :_reduce_73, - 1, 95, :_reduce_74, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 1, 117, :_reduce_none, - 3, 77, :_reduce_82, - 3, 77, :_reduce_83, - 3, 86, :_reduce_84, - 0, 104, :_reduce_85, - 1, 104, :_reduce_86, - 3, 104, :_reduce_87, - 3, 122, :_reduce_88, - 3, 124, :_reduce_89, - 1, 125, :_reduce_none, - 1, 125, :_reduce_none, - 0, 107, :_reduce_92, - 1, 107, :_reduce_93, - 3, 107, :_reduce_94, - 1, 126, :_reduce_none, - 3, 126, :_reduce_96, - 1, 115, :_reduce_none, - 1, 115, :_reduce_none, - 1, 115, :_reduce_none, - 1, 115, :_reduce_none, + 1, 111, :_reduce_none, + 3, 111, :_reduce_59, + 1, 112, :_reduce_none, + 3, 112, :_reduce_61, + 1, 113, :_reduce_62, + 1, 113, :_reduce_63, + 3, 114, :_reduce_64, + 3, 114, :_reduce_65, 1, 115, :_reduce_none, 1, 115, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 1, 123, :_reduce_none, - 4, 97, :_reduce_115, - 3, 97, :_reduce_116, - 1, 99, :_reduce_117, - 2, 99, :_reduce_118, - 2, 129, :_reduce_119, - 1, 130, :_reduce_120, - 2, 130, :_reduce_121, - 1, 96, :_reduce_122, - 4, 90, :_reduce_123, - 4, 90, :_reduce_124, - 2, 79, :_reduce_125, - 5, 131, :_reduce_126, - 4, 131, :_reduce_127, - 0, 132, :_reduce_none, - 2, 132, :_reduce_129, - 4, 132, :_reduce_130, - 3, 132, :_reduce_131, - 1, 120, :_reduce_none, - 3, 120, :_reduce_133, - 3, 120, :_reduce_134, - 3, 120, :_reduce_135, - 3, 120, :_reduce_136, - 3, 120, :_reduce_137, - 3, 120, :_reduce_138, - 3, 120, :_reduce_139, - 3, 120, :_reduce_140, - 3, 120, :_reduce_141, - 2, 120, :_reduce_142, - 3, 120, :_reduce_143, - 3, 120, :_reduce_144, - 3, 120, :_reduce_145, - 3, 120, :_reduce_146, - 3, 120, :_reduce_147, - 3, 120, :_reduce_148, - 2, 120, :_reduce_149, - 3, 120, :_reduce_150, - 3, 120, :_reduce_151, - 3, 120, :_reduce_152, - 5, 78, :_reduce_153, - 1, 134, :_reduce_none, - 2, 134, :_reduce_155, - 5, 135, :_reduce_156, - 4, 135, :_reduce_157, - 1, 136, :_reduce_none, - 3, 136, :_reduce_159, - 3, 98, :_reduce_160, + 4, 117, :_reduce_68, + 1, 103, :_reduce_69, + 3, 103, :_reduce_70, + 0, 104, :_reduce_none, + 1, 104, :_reduce_none, + 1, 119, :_reduce_73, + 1, 94, :_reduce_74, + 1, 96, :_reduce_75, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 1, 118, :_reduce_none, + 3, 78, :_reduce_83, + 3, 78, :_reduce_84, + 3, 87, :_reduce_85, + 0, 105, :_reduce_86, + 1, 105, :_reduce_87, + 3, 105, :_reduce_88, + 3, 123, :_reduce_89, + 3, 125, :_reduce_90, + 1, 126, :_reduce_none, + 1, 126, :_reduce_none, + 0, 108, :_reduce_93, + 1, 108, :_reduce_94, + 3, 108, :_reduce_95, + 1, 127, :_reduce_96, + 3, 127, :_reduce_97, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 116, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 1, 124, :_reduce_none, + 4, 98, :_reduce_116, + 3, 98, :_reduce_117, + 1, 100, :_reduce_118, + 2, 100, :_reduce_119, + 2, 130, :_reduce_120, + 1, 131, :_reduce_121, + 2, 131, :_reduce_122, + 1, 97, :_reduce_123, + 4, 91, :_reduce_124, + 4, 91, :_reduce_125, + 2, 80, :_reduce_126, + 5, 132, :_reduce_127, + 4, 132, :_reduce_128, + 0, 133, :_reduce_none, + 2, 133, :_reduce_130, + 4, 133, :_reduce_131, + 3, 133, :_reduce_132, + 1, 121, :_reduce_none, + 3, 121, :_reduce_134, + 3, 121, :_reduce_135, + 3, 121, :_reduce_136, + 3, 121, :_reduce_137, + 3, 121, :_reduce_138, + 3, 121, :_reduce_139, + 3, 121, :_reduce_140, + 3, 121, :_reduce_141, + 3, 121, :_reduce_142, + 2, 121, :_reduce_143, + 3, 121, :_reduce_144, + 3, 121, :_reduce_145, + 3, 121, :_reduce_146, + 3, 121, :_reduce_147, + 3, 121, :_reduce_148, + 3, 121, :_reduce_149, + 2, 121, :_reduce_150, + 3, 121, :_reduce_151, + 3, 121, :_reduce_152, + 3, 121, :_reduce_153, + 5, 79, :_reduce_154, + 1, 135, :_reduce_155, + 2, 135, :_reduce_156, + 5, 136, :_reduce_157, + 4, 136, :_reduce_158, + 1, 137, :_reduce_159, + 3, 137, :_reduce_160, + 3, 99, :_reduce_161, + 1, 139, :_reduce_none, + 4, 139, :_reduce_163, + 1, 141, :_reduce_none, + 3, 141, :_reduce_165, + 3, 140, :_reduce_166, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, 1, 138, :_reduce_none, - 4, 138, :_reduce_162, - 1, 140, :_reduce_none, - 3, 140, :_reduce_164, - 3, 139, :_reduce_165, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_none, - 1, 137, :_reduce_173, - 1, 137, :_reduce_none, - 1, 141, :_reduce_175, - 1, 142, :_reduce_none, - 3, 142, :_reduce_177, - 2, 80, :_reduce_178, - 6, 82, :_reduce_179, - 5, 82, :_reduce_180, - 7, 83, :_reduce_181, - 6, 83, :_reduce_182, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, + 1, 138, :_reduce_none, + 1, 138, :_reduce_174, + 1, 138, :_reduce_none, + 1, 142, :_reduce_176, + 1, 143, :_reduce_none, + 3, 143, :_reduce_178, + 2, 81, :_reduce_179, + 6, 83, :_reduce_180, + 5, 83, :_reduce_181, + 7, 84, :_reduce_182, 6, 84, :_reduce_183, - 5, 84, :_reduce_184, - 1, 106, :_reduce_185, - 1, 101, :_reduce_186, - 1, 101, :_reduce_187, - 1, 101, :_reduce_188, - 1, 145, :_reduce_none, - 3, 145, :_reduce_190, - 1, 147, :_reduce_191, + 6, 85, :_reduce_184, + 5, 85, :_reduce_185, + 1, 107, :_reduce_186, + 1, 102, :_reduce_187, + 1, 102, :_reduce_188, + 1, 102, :_reduce_189, + 1, 146, :_reduce_190, + 3, 146, :_reduce_191, 1, 148, :_reduce_192, - 1, 148, :_reduce_193, - 1, 148, :_reduce_194, - 1, 148, :_reduce_none, - 0, 72, :_reduce_196, - 0, 149, :_reduce_197, - 1, 143, :_reduce_none, - 3, 143, :_reduce_199, - 3, 143, :_reduce_200, - 1, 150, :_reduce_none, - 3, 150, :_reduce_202, - 3, 151, :_reduce_203, - 1, 151, :_reduce_204, - 3, 151, :_reduce_205, - 1, 151, :_reduce_206, - 1, 146, :_reduce_none, - 2, 146, :_reduce_208, + 1, 149, :_reduce_193, + 1, 149, :_reduce_194, + 1, 149, :_reduce_195, + 1, 149, :_reduce_none, + 0, 72, :_reduce_197, + 0, 150, :_reduce_198, 1, 144, :_reduce_none, - 2, 144, :_reduce_210, - 1, 152, :_reduce_none, - 1, 152, :_reduce_none, - 1, 94, :_reduce_213, - 3, 119, :_reduce_214, - 4, 119, :_reduce_215, - 2, 119, :_reduce_216, - 1, 127, :_reduce_none, - 1, 127, :_reduce_none, - 0, 105, :_reduce_none, - 1, 105, :_reduce_220, - 1, 133, :_reduce_221, - 3, 128, :_reduce_222, - 4, 128, :_reduce_223, - 2, 128, :_reduce_224, + 3, 144, :_reduce_200, + 3, 144, :_reduce_201, + 1, 151, :_reduce_none, + 3, 151, :_reduce_203, + 3, 152, :_reduce_204, + 1, 152, :_reduce_205, + 3, 152, :_reduce_206, + 1, 152, :_reduce_207, + 1, 147, :_reduce_none, + 2, 147, :_reduce_209, + 1, 145, :_reduce_none, + 2, 145, :_reduce_211, 1, 153, :_reduce_none, - 3, 153, :_reduce_226, + 1, 153, :_reduce_none, + 1, 95, :_reduce_214, + 3, 120, :_reduce_215, + 4, 120, :_reduce_216, + 2, 120, :_reduce_217, + 1, 128, :_reduce_none, + 1, 128, :_reduce_none, + 0, 106, :_reduce_none, + 1, 106, :_reduce_221, + 1, 134, :_reduce_222, + 3, 129, :_reduce_223, + 4, 129, :_reduce_224, + 2, 129, :_reduce_225, + 1, 154, :_reduce_none, 3, 154, :_reduce_227, - 1, 155, :_reduce_228, - 1, 155, :_reduce_229, - 4, 121, :_reduce_230, - 1, 100, :_reduce_none, - 4, 100, :_reduce_232 ] + 3, 155, :_reduce_228, + 1, 156, :_reduce_229, + 1, 156, :_reduce_230, + 4, 122, :_reduce_231, + 1, 101, :_reduce_none, + 4, 101, :_reduce_233 ] -racc_reduce_n = 233 +racc_reduce_n = 234 -racc_shift_n = 384 +racc_shift_n = 385 racc_action_table = [ - 256, 257, 228, 82, 54, 72, 75, 181, 251, 48, - 72, 75, 194, 205, 210, 163, 156, 348, 46, 47, - 344, 184, 201, 203, 206, 209, 162, 352, 54, 182, - 351, 169, 54, -168, 72, 75, 241, 242, 102, 305, - 106, 158, 58, 193, 230, 60, 204, 208, 193, 306, - 213, 196, 197, 198, 200, 202, 97, 207, 211, 72, - 75, 72, 75, 163, 199, 59, 58, 71, 245, 60, - 58, 83, 86, 60, 162, 92, 244, 72, 75, 169, - 78, 100, 352, 269, 89, 351, 63, 94, 64, 59, - 228, 326, 71, 59, 162, 59, 83, 86, 83, 268, - 92, 65, 92, 184, 76, 78, 307, 137, 163, 89, - 162, 89, 72, 75, 83, 268, 241, 242, 92, 162, - 59, 163, 59, 137, 169, 62, 254, 89, 207, 211, - 72, 75, 162, 308, 102, 199, 106, 169, 59, 255, - 213, 196, 197, 198, -166, 162, 309, 207, 211, 83, - 268, 310, 97, 92, 199, 72, 75, 355, 137, 102, - -170, 106, 89, 71, 218, 356, 173, 83, 86, 220, - 313, 92, -171, 59, 72, 75, 78, 100, 37, 218, - 89, 249, 38, 94, 220, 246, 247, 173, 71, 11, - 210, 59, 83, 86, 246, 367, 92, 271, 201, 37, - -167, 78, 37, 38, 270, 89, 38, 71, 246, 247, - 11, 83, 86, 11, 14, 92, 59, 72, 75, 76, - 78, 102, 278, 106, 89, 277, 213, 196, 197, 198, - 200, 202, 275, 207, 211, 59, 246, 274, 152, 97, - 199, 37, 318, 72, 75, 127, 319, 102, -169, 106, - 71, 63, 11, 14, 83, 86, -167, 37, 92, 207, - 211, 127, -169, 78, 100, 97, 199, 89, 11, 14, - 94, -166, 117, 72, 75, -185, 71, 82, 59, 336, - 83, 86, 197, 198, 92, 231, 338, 207, 211, 78, - 100, 181, 48, 89, 199, 74, 94, 240, -168, 72, - 75, 241, 242, 102, 59, 106, 71, 184, 176, 37, - 83, 86, 59, 38, 92, 345, 322, 175, 76, 78, - 11, 97, -172, 89, -171, 72, 75, -170, 59, 102, - 214, 106, 71, 64, 59, 215, 83, 86, 173, 217, - 92, -23, -23, -23, -23, 78, 100, 97, 155, 89, - 72, 75, 94, 122, 102, 152, 106, 82, 71, 223, - 59, 122, 83, 86, 72, 75, 92, -168, 102, 225, - 106, 78, 100, -166, 276, 89, 226, 117, 94, 44, - 45, 41, 42, 71, -169, -167, 59, 83, 86, 72, - 75, 92, 226, 102, 229, 106, 78, 71, 52, -168, - 89, 83, 86, 72, 75, 92, -166, 102, -169, 106, - 78, 59, 197, 198, 89, -167, -171, 207, 211, 365, - 231, 152, 71, 234, 199, 59, 83, 86, 50, 210, - 92, -21, -21, -21, -21, 78, 71, 201, 372, 89, - 83, 86, 49, 374, 92, 72, 75, 228, -220, 78, - 59, 226, 354, 89, 377, 72, 75, 40, 39, 102, - 237, 106, 341, nil, 59, 213, 196, 197, 198, 200, - 202, nil, 207, 211, nil, nil, nil, 97, 162, 199, - nil, nil, 83, 268, nil, nil, 92, nil, 71, nil, - nil, 137, 83, 86, nil, 89, 92, 44, 45, 41, - 42, 78, 100, 72, 75, 89, 59, 102, 94, 106, - 213, 196, 197, 198, 200, 202, 59, 207, 211, nil, - 213, 196, 197, 198, 199, 97, nil, 207, 211, 72, - 75, nil, nil, 102, 199, 106, 71, nil, nil, nil, - 83, 86, nil, nil, 92, nil, nil, nil, nil, 78, - 100, 97, nil, 89, nil, nil, 94, nil, nil, 72, - 75, nil, 71, 102, 59, 106, 83, 86, nil, nil, - 92, nil, nil, nil, nil, 78, 100, nil, nil, 89, - nil, 97, 94, nil, nil, 72, 75, nil, nil, 102, - 59, 106, 71, nil, nil, nil, 83, 86, nil, nil, - 92, nil, nil, nil, nil, 78, 100, 97, nil, 89, - 72, 75, 94, nil, 102, nil, 106, nil, 71, nil, - 59, nil, 83, 86, 72, 75, 92, nil, 102, nil, - nil, 78, 100, nil, nil, 89, nil, nil, 94, nil, - nil, nil, nil, 71, nil, nil, 59, 83, 86, 72, - 75, 92, nil, 102, nil, 106, 78, 71, nil, nil, - 89, 83, 143, nil, nil, 92, nil, nil, nil, nil, - 137, 59, nil, nil, 89, 72, 75, nil, nil, 102, - nil, 106, 71, nil, nil, 59, 83, 86, nil, nil, - 92, nil, nil, nil, nil, 78, nil, 97, nil, 89, - nil, 72, 75, nil, nil, 102, nil, 106, 71, nil, - 59, nil, 83, 86, nil, nil, 92, nil, nil, nil, - nil, 78, 100, 97, nil, 89, nil, nil, 94, nil, - nil, 72, 75, nil, 71, 102, 59, 106, 83, 86, - nil, nil, 92, nil, nil, nil, nil, 78, 100, nil, - nil, 89, nil, 97, 94, nil, nil, 72, 75, nil, - nil, 102, 59, 106, 71, nil, nil, nil, 83, 86, - nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, - nil, 89, 72, 75, 94, nil, 102, nil, 106, nil, - 71, nil, 59, nil, 83, 86, nil, nil, 92, nil, - nil, nil, nil, 78, 100, nil, nil, 89, 72, 75, - 94, nil, 102, nil, 106, 71, nil, nil, 59, 83, - 86, nil, nil, 92, nil, nil, nil, nil, 78, nil, - 97, nil, 89, nil, 72, 75, nil, nil, 102, nil, - 106, 71, nil, 59, nil, 83, 86, nil, nil, 92, - nil, nil, 72, 75, 78, 100, 97, nil, 89, 72, - 75, 94, nil, 102, nil, 106, nil, 71, nil, 59, - nil, 83, 86, nil, nil, 92, nil, nil, nil, nil, - 78, 100, nil, nil, 89, 162, nil, 94, nil, 83, - 268, nil, 71, 92, nil, 59, 83, 86, 137, nil, - 92, nil, 89, nil, nil, 78, 72, 75, nil, 89, - 102, nil, 106, 59, nil, nil, nil, nil, nil, nil, - 59, nil, nil, nil, nil, 72, 75, nil, 97, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 71, - nil, nil, nil, 83, 86, nil, nil, 92, 177, nil, - 72, 75, 78, 100, nil, nil, 89, nil, 71, 94, - nil, nil, 83, 86, nil, nil, 92, 59, 72, 75, - 76, 78, 102, 339, 106, 89, nil, nil, nil, nil, - nil, nil, nil, 71, nil, nil, 59, 83, 86, nil, - 97, 92, nil, 72, 75, 76, 78, 102, nil, 106, - 89, 71, nil, 72, 75, 83, 86, nil, nil, 92, - nil, 59, nil, nil, 78, 100, nil, nil, 89, 72, - 75, 94, nil, nil, nil, nil, 71, nil, nil, 59, - 83, 86, nil, nil, 92, nil, 162, nil, nil, 78, - 83, 268, nil, 89, 92, nil, 72, 75, nil, 137, - 102, nil, 162, 89, 59, nil, 83, 268, nil, nil, - 92, nil, 72, 75, 59, 137, 102, nil, 106, 89, - nil, nil, 72, 75, nil, nil, 102, nil, 106, 71, - 59, nil, nil, 83, 268, nil, nil, 92, nil, nil, - nil, nil, 137, nil, 97, 71, 89, nil, nil, 83, - 86, nil, nil, 92, nil, 71, nil, 59, 78, 83, - 86, nil, 89, 92, nil, nil, nil, nil, 78, 100, - 72, 75, 89, 59, 102, 94, 106, 213, 196, 197, - 198, 200, 202, 59, 207, 211, nil, nil, nil, 72, - 75, 199, 97, 102, 189, 106, 72, 75, nil, nil, - 102, nil, 106, 71, nil, nil, nil, 83, 86, nil, - nil, 92, nil, nil, nil, nil, 78, 100, 72, 75, - 89, nil, 71, 94, nil, nil, 83, 86, nil, 71, - 92, 59, nil, 83, 86, 78, nil, 92, nil, 89, - nil, nil, 78, 72, 75, nil, 89, 102, nil, 106, - 59, 162, nil, nil, nil, 83, 268, 59, nil, 92, - nil, 72, 75, nil, 137, 102, nil, 106, 89, nil, - nil, nil, nil, nil, nil, nil, 71, nil, nil, 59, - 83, 86, nil, 97, 92, nil, nil, nil, nil, 78, - nil, 72, 75, 89, 71, 102, nil, 106, 83, 86, - nil, nil, 92, nil, 59, nil, nil, 78, 100, nil, - nil, 89, nil, 97, 94, nil, nil, 72, 75, nil, - nil, 102, 59, 106, 71, nil, nil, nil, 83, 86, - nil, nil, 92, nil, nil, nil, nil, 78, 100, 97, - nil, 89, nil, nil, 94, nil, nil, nil, nil, nil, - 71, nil, 59, nil, 83, 86, 212, nil, 92, nil, - nil, nil, nil, 78, 100, 205, 210, 89, nil, nil, - 94, nil, nil, nil, 201, 203, 206, 209, 59, nil, - 205, 210, nil, nil, nil, nil, nil, nil, nil, 201, - 203, 206, 209, nil, nil, nil, nil, nil, 204, 208, - nil, nil, 213, 196, 197, 198, 200, 202, nil, 207, - 211, nil, nil, 204, 208, nil, 199, 213, 196, 197, - 198, 200, 202, nil, 207, 211, 205, 210, nil, nil, - nil, 199, nil, nil, nil, 201, 203, 206, 209, nil, - nil, 205, 210, nil, nil, nil, nil, nil, nil, nil, - 201, 203, 206, 209, nil, nil, nil, nil, nil, 204, - 208, nil, nil, 213, 196, 197, 198, 200, 202, nil, - 207, 211, nil, nil, 204, 208, nil, 199, 213, 196, - 197, 198, 200, 202, nil, 207, 211, 205, 210, nil, - nil, nil, 199, nil, nil, nil, 201, 203, 206, 209, - nil, nil, 205, 210, nil, nil, nil, nil, nil, nil, - 273, 201, 203, 206, 209, nil, nil, nil, nil, nil, - nil, 208, nil, nil, 213, 196, 197, 198, 200, 202, - nil, 207, 211, nil, nil, 204, 208, nil, 199, 213, - 196, 197, 198, 200, 202, nil, 207, 211, 205, 210, - nil, nil, nil, 199, nil, nil, nil, 201, 203, 206, - 209, nil, nil, 26, 210, 33, 1, nil, 7, 12, - nil, 17, 201, 23, nil, 29, nil, 3, nil, nil, - 11, 14, nil, 210, nil, 213, 196, 197, 198, 200, - 202, 201, 207, 211, nil, nil, nil, nil, nil, 199, - 213, 196, 197, 198, 200, 202, nil, 207, 211, nil, - nil, 324, nil, nil, 199, nil, nil, nil, nil, 213, - 196, 197, 198, 200, 202, nil, 207, 211, nil, nil, - 379, nil, 26, 199, 33, 1, nil, 7, 12, nil, - 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, - 14, 26, 382, 33, 1, nil, 7, 12, nil, 17, - nil, 23, nil, 29, nil, 3, nil, nil, 11, 14, - nil, 296, nil, 26, nil, 33, 1, nil, 7, 12, - nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, - 11, 14, 26, 364, 33, 1, nil, 7, 12, nil, - 17, nil, 23, nil, 29, nil, 3, nil, nil, 11, - 14, nil, 381, nil, 26, nil, 33, 1, nil, 7, - 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, - nil, 11, 14, 26, 383, 33, 1, nil, 7, 12, - nil, 17, nil, 23, nil, 29, nil, 3, nil, nil, - 11, 14, nil, 357, nil, 26, nil, 33, 1, nil, - 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, - nil, nil, 11, 14, 26, 363, 33, 1, nil, 7, - 12, nil, 17, nil, 23, nil, 29, nil, 3, nil, - nil, 11, 14, nil, 375, nil, 26, nil, 33, 1, - nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, - 3, nil, nil, 11, 14, 26, 304, 33, 1, nil, - 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, - nil, nil, 11, 14, nil, 349, nil, 26, nil, 33, - 1, nil, 7, 12, nil, 17, nil, 23, nil, 29, - nil, 3, nil, nil, 11, 14, 26, nil, 33, 1, - nil, 7, 12, nil, 17, nil, 23, nil, 29, nil, - 3, nil, nil, 11, 14, 26, nil, 33, 1, nil, - 7, 12, nil, 17, nil, 23, nil, 29, nil, 3, - nil, nil, 11, 14 ] + 242, 243, 55, 231, 356, 112, 157, 113, 78, 298, + 68, 71, 357, 181, 186, 326, 344, 340, 55, 295, + 114, 231, 177, 179, 182, 185, 170, 294, 68, 71, + 286, 158, 100, 285, 103, 68, 71, 291, 292, 55, + 59, 291, 292, 61, 111, 233, 180, 184, 198, 231, + 189, 172, 173, 174, 176, 178, 59, 183, 187, 61, + -168, 66, 170, 60, 175, 79, 81, 186, 202, 88, + 112, 166, 79, 252, 74, 177, 88, 59, 84, 60, + 61, 139, 68, 71, 333, 84, 100, 117, 103, 60, + 36, -170, 68, 71, 38, 306, 60, 307, 203, 240, + 60, 10, 203, 189, 172, 173, 174, 176, 178, 202, + 183, 187, 241, 202, 209, 66, 218, 175, 209, 79, + 81, 219, 284, 88, 309, 202, 256, 283, 74, 79, + 252, 308, 84, 88, 203, 68, 71, 310, 139, 100, + 203, 103, 84, 60, 218, 202, 256, 367, 36, 219, + 209, 202, 38, 60, 68, 71, 209, 95, 100, 10, + 103, 68, 71, 68, 71, 100, 337, 103, 66, 335, + 199, 154, 79, 81, 173, 174, 88, 183, 187, 183, + 187, 74, 99, 95, 175, 84, 175, 66, 90, 311, + 337, 79, 81, 335, 66, 88, 60, 287, 79, 81, + 74, 198, 88, 315, 84, 68, 71, 74, 99, -172, + 213, 84, 68, 71, 90, 60, 100, 36, 103, 68, + 71, 38, 60, 100, 318, 103, 68, 71, 10, 15, + 36, -167, 213, 355, 38, 167, 36, 313, 202, 154, + 127, 10, 79, 252, 323, 66, 88, 10, 15, 79, + 81, 139, 66, 88, 166, 84, 79, 81, 74, 202, + 88, 229, 84, 79, 252, 74, 60, 88, 49, 84, + 68, 71, 139, 60, 78, -186, 84, 47, 48, 49, + 60, 329, 36, 170, 183, 187, 127, 60, -169, 68, + 71, 175, 70, 10, 15, 68, 71, 161, -171, 100, + 289, 103, -169, 66, 291, 292, 60, 79, 81, 258, + -167, 88, -170, 256, 257, 72, 74, 95, -168, 60, + 84, 156, 66, 154, 68, 71, 79, 81, 66, 122, + 88, 60, 79, 81, 72, 74, 88, -170, -173, 84, + -172, 74, 99, 68, 71, 84, -171, 100, 90, 103, + 60, 200, 334, 68, 71, 213, 60, 202, 215, 254, + 338, 79, 252, 173, 174, 88, 122, 296, 183, 187, + 139, 256, 257, 216, 84, 175, 66, 234, 68, 71, + 79, 81, 113, 117, 88, 60, 202, 217, 78, 74, + 79, 252, 353, 84, 88, 53, 68, 71, 223, 139, + 100, 260, 103, 84, 60, 43, 44, 40, 41, 358, + 52, 66, 51, 225, 60, 79, 81, -169, 229, 88, + 365, 68, 71, 72, 74, 100, 238, 103, 84, 66, + 228, -167, 234, 79, 81, 372, 373, 88, -169, 60, + -167, -170, 74, 95, -168, -172, 84, 68, 71, 45, + 375, 100, 229, 103, 66, -221, 232, 60, 79, 81, + 378, 39, 88, -24, -24, -24, -24, 74, 99, 95, + -168, 84, 383, 384, 90, nil, nil, 68, 71, nil, + 66, 100, 60, 103, 79, 81, nil, nil, 88, -22, + -22, -22, -22, 74, 99, nil, nil, 84, nil, 95, + 90, nil, nil, 68, 71, nil, nil, 100, 60, 103, + 66, nil, nil, nil, 79, 81, nil, nil, 88, 43, + 44, 40, 41, 74, 99, 95, nil, 84, nil, nil, + 90, nil, nil, 68, 71, nil, 66, 100, 60, 103, + 79, 81, nil, nil, 88, nil, nil, nil, nil, 74, + 99, nil, nil, 84, nil, 95, 90, nil, nil, 68, + 71, nil, nil, 100, 60, 103, 66, nil, nil, nil, + 79, 81, nil, nil, 88, nil, nil, 68, 71, 74, + 99, 100, nil, 84, 68, 71, 90, nil, 100, nil, + 103, nil, 66, nil, 60, nil, 79, 81, nil, nil, + 88, nil, nil, nil, nil, 74, 95, nil, nil, 84, + 66, nil, nil, nil, 79, 144, nil, 66, 88, nil, + 60, 79, 81, 139, nil, 88, nil, 84, nil, nil, + 74, 99, nil, nil, 84, 68, 71, 90, 60, 100, + nil, 103, nil, nil, nil, 60, nil, nil, nil, nil, + nil, nil, nil, nil, 68, 71, nil, 95, 100, nil, + 103, 68, 71, nil, nil, 100, nil, 103, 66, nil, + nil, nil, 79, 81, nil, nil, 88, nil, nil, 68, + 71, 74, 99, nil, nil, 84, nil, 66, 90, nil, + nil, 79, 81, nil, 66, 88, 60, nil, 79, 81, + 74, nil, 88, nil, 84, 68, 71, 74, nil, nil, + nil, 84, 202, nil, nil, 60, 79, 252, nil, nil, + 88, nil, 60, nil, nil, 139, 68, 71, 162, 84, + 100, nil, 103, nil, nil, nil, nil, nil, 66, nil, + 60, nil, 79, 81, nil, nil, 88, nil, 95, nil, + 72, 74, 68, 71, nil, 84, 100, nil, 103, 66, + nil, nil, nil, 79, 81, nil, 60, 88, nil, nil, + nil, nil, 74, 99, 95, nil, 84, 68, 71, 90, + nil, nil, nil, nil, nil, 66, nil, 60, nil, 79, + 81, nil, nil, 88, nil, nil, nil, nil, 74, 99, + 327, nil, 84, 68, 71, 90, nil, 100, nil, 103, + 66, nil, nil, 60, 79, 81, nil, nil, 88, nil, + nil, nil, 72, 74, nil, 95, nil, 84, 68, 71, + nil, nil, 100, nil, 103, nil, 66, nil, 60, nil, + 79, 81, 68, 71, 88, nil, 100, nil, 103, 74, + 99, nil, nil, 84, nil, nil, 90, nil, nil, nil, + nil, 66, nil, nil, 60, 79, 81, 68, 71, 88, + nil, 100, nil, 103, 74, 66, nil, nil, 84, 79, + 81, 68, 71, 88, nil, 100, nil, nil, 74, 60, + nil, nil, 84, nil, nil, nil, nil, nil, nil, nil, + 66, nil, nil, 60, 79, 81, nil, nil, 88, nil, + nil, 68, 71, 74, 66, nil, nil, 84, 79, 252, + nil, nil, 88, nil, nil, nil, nil, 139, 60, 68, + 71, 84, nil, 100, nil, 103, nil, nil, nil, nil, + nil, nil, 60, nil, 202, nil, nil, nil, 79, 252, + nil, 95, 88, nil, nil, nil, nil, 139, nil, 68, + 71, 84, 66, 100, nil, 103, 79, 81, nil, nil, + 88, nil, 60, nil, nil, 74, 99, nil, nil, 84, + nil, 95, 90, nil, nil, 68, 71, nil, nil, 100, + 60, 103, 66, nil, nil, nil, 79, 81, nil, nil, + 88, nil, nil, nil, nil, 74, 99, 95, nil, 84, + nil, nil, 90, nil, nil, 68, 71, nil, 66, 100, + 60, 103, 79, 81, nil, nil, 88, nil, nil, nil, + nil, 74, 99, nil, nil, 84, nil, 95, 90, nil, + nil, 68, 71, nil, nil, 100, 60, 103, 66, nil, + nil, nil, 79, 81, nil, nil, 88, nil, nil, nil, + nil, 74, 99, 95, nil, 84, nil, nil, 90, nil, + nil, 68, 71, nil, 66, 100, 60, 103, 79, 81, + nil, nil, 88, nil, nil, nil, nil, 74, 99, nil, + nil, 84, nil, 95, 90, nil, nil, 68, 71, nil, + nil, 100, 60, 103, 66, nil, nil, nil, 79, 81, + nil, nil, 88, nil, nil, nil, nil, 74, 99, 95, + nil, 84, nil, nil, 90, nil, nil, 68, 71, nil, + 66, 100, 60, 103, 79, 81, nil, nil, 88, nil, + nil, nil, nil, 74, 99, nil, nil, 84, nil, 95, + 90, nil, nil, 68, 71, nil, nil, 100, 60, 103, + 66, nil, nil, nil, 79, 81, nil, nil, 88, nil, + nil, nil, nil, 74, 99, 95, nil, 84, 68, 71, + 90, nil, 100, 193, 103, nil, 66, nil, 60, nil, + 79, 81, nil, nil, 88, nil, nil, nil, nil, 74, + 99, nil, nil, 84, 68, 71, 90, nil, 100, nil, + 103, 66, nil, nil, 60, 79, 81, nil, nil, 88, + nil, nil, nil, nil, 74, nil, 95, nil, 84, nil, + 68, 71, nil, nil, 100, nil, 103, 66, nil, 60, + nil, 79, 81, nil, nil, 88, nil, nil, nil, nil, + 74, 99, 95, nil, 84, nil, nil, 90, nil, nil, + nil, nil, nil, 66, nil, 60, nil, 79, 81, 188, + nil, 88, nil, nil, nil, nil, 74, 99, 181, 186, + 84, nil, nil, 90, nil, nil, nil, 177, 179, 182, + 185, 60, nil, 181, 186, nil, nil, nil, nil, nil, + nil, 282, 177, 179, 182, 185, nil, nil, nil, nil, + nil, 180, 184, nil, nil, 189, 172, 173, 174, 176, + 178, nil, 183, 187, nil, nil, 180, 184, nil, 175, + 189, 172, 173, 174, 176, 178, nil, 183, 187, 181, + 186, nil, nil, nil, 175, nil, nil, nil, 177, 179, + 182, 185, nil, nil, 181, 186, nil, nil, nil, nil, + nil, nil, nil, 177, 179, 182, 185, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 189, 172, 173, 174, + 176, 178, nil, 183, 187, nil, nil, 180, 184, nil, + 175, 189, 172, 173, 174, 176, 178, nil, 183, 187, + 181, 186, nil, nil, nil, 175, nil, nil, nil, 177, + 179, 182, 185, nil, nil, 181, 186, nil, nil, nil, + nil, nil, nil, nil, 177, 179, 182, 185, nil, nil, + nil, nil, nil, 180, 184, nil, nil, 189, 172, 173, + 174, 176, 178, nil, 183, 187, nil, nil, nil, 184, + nil, 175, 189, 172, 173, 174, 176, 178, nil, 183, + 187, 181, 186, nil, nil, nil, 175, nil, nil, nil, + 177, 179, 182, 185, nil, nil, nil, 186, nil, 189, + 172, 173, 174, 176, 178, 177, 183, 187, nil, nil, + nil, nil, nil, 175, 180, 184, 186, nil, 189, 172, + 173, 174, 176, 178, 177, 183, 187, nil, nil, nil, + nil, 186, 175, 189, 172, 173, 174, 176, 178, 177, + 183, 187, nil, nil, nil, nil, nil, 175, nil, nil, + nil, nil, 189, 172, 173, 174, 176, 178, nil, 183, + 187, 280, nil, nil, nil, nil, 175, 189, 172, 173, + 174, 176, 178, nil, 183, 187, nil, nil, nil, nil, + 325, 175, 26, nil, 32, 1, nil, 8, 11, nil, + 18, nil, 23, nil, 29, nil, 2, nil, nil, 10, + 15, 26, 363, 32, 1, nil, 8, 11, nil, 18, + nil, 23, nil, 29, nil, 2, nil, nil, 10, 15, + nil, 382, nil, 26, nil, 32, 1, nil, 8, 11, + nil, 18, nil, 23, nil, 29, nil, 2, nil, nil, + 10, 15, 26, 380, 32, 1, nil, 8, 11, nil, + 18, nil, 23, nil, 29, nil, 2, nil, nil, 10, + 15, nil, 376, nil, 26, nil, 32, 1, nil, 8, + 11, nil, 18, nil, 23, nil, 29, nil, 2, nil, + nil, 10, 15, 26, 305, 32, 1, nil, 8, 11, + nil, 18, nil, 23, nil, 29, nil, 2, nil, nil, + 10, 15, nil, nil, nil, 26, nil, 32, 1, nil, + 8, 11, nil, 18, nil, 23, nil, 29, nil, 2, + nil, nil, 10, 15, 26, nil, 32, 1, nil, 8, + 11, nil, 18, nil, 23, nil, 29, nil, 2, nil, + nil, 10, 15, 26, nil, 32, 1, nil, 8, 11, + nil, 18, nil, 23, nil, 29, nil, 2, nil, nil, + 10, 15, 26, nil, 32, 1, nil, 8, 11, nil, + 18, nil, 23, nil, 29, nil, 2, nil, nil, 10, + 15, 189, 172, 173, 174, 176, 178, nil, 183, 187, + 189, 172, 173, 174, nil, 175, nil, 183, 187, 189, + 172, 173, 174, nil, 175, nil, 183, 187, nil, nil, + nil, nil, nil, 175 ] racc_action_check = [ - 180, 180, 152, 86, 156, 106, 106, 272, 174, 7, - 277, 277, 106, 180, 180, 65, 55, 277, 7, 7, - 272, 86, 180, 180, 180, 180, 65, 296, 17, 80, - 296, 65, 158, 95, 202, 202, 174, 174, 202, 218, - 202, 55, 156, 106, 152, 156, 180, 180, 277, 219, - 180, 180, 180, 180, 180, 180, 202, 180, 180, 181, - 181, 368, 368, 239, 180, 156, 17, 202, 165, 17, - 158, 202, 202, 158, 239, 202, 165, 182, 182, 239, - 202, 202, 349, 182, 202, 349, 22, 202, 22, 17, - 143, 243, 181, 158, 368, 202, 181, 181, 368, 368, - 181, 22, 368, 143, 181, 181, 220, 368, 163, 181, - 182, 368, 355, 355, 182, 182, 243, 243, 182, 163, - 181, 62, 368, 182, 163, 22, 178, 182, 281, 281, - 351, 351, 62, 221, 351, 281, 351, 62, 182, 178, - 285, 285, 285, 285, 101, 355, 221, 285, 285, 355, - 355, 224, 351, 355, 285, 341, 341, 300, 355, 341, - 91, 341, 355, 351, 308, 300, 226, 351, 351, 308, - 227, 351, 90, 355, 184, 184, 351, 351, 12, 122, - 351, 171, 12, 351, 122, 171, 171, 229, 341, 12, - 286, 351, 341, 341, 343, 343, 341, 184, 286, 1, - 87, 341, 30, 1, 183, 341, 30, 184, 183, 183, - 1, 184, 184, 30, 30, 184, 341, 196, 196, 184, - 184, 196, 195, 196, 184, 195, 286, 286, 286, 286, - 286, 286, 188, 286, 286, 184, 188, 188, 231, 196, - 286, 120, 232, 197, 197, 120, 233, 197, 103, 197, - 196, 85, 120, 120, 196, 196, 105, 43, 196, 280, - 280, 43, 84, 196, 196, 197, 280, 196, 43, 43, - 196, 81, 215, 23, 23, 78, 197, 23, 196, 250, - 197, 197, 279, 279, 197, 252, 253, 279, 279, 197, - 197, 77, 71, 197, 279, 23, 197, 160, 68, 26, - 26, 160, 160, 26, 197, 26, 23, 268, 67, 234, - 23, 23, 211, 234, 23, 274, 234, 66, 23, 23, - 234, 26, 107, 23, 108, 198, 198, 109, 207, 198, - 114, 198, 26, 115, 23, 119, 26, 26, 64, 121, - 26, 35, 35, 35, 35, 26, 26, 198, 52, 26, - 29, 29, 26, 51, 29, 50, 29, 127, 198, 132, - 26, 36, 198, 198, 307, 307, 198, 133, 307, 136, - 307, 198, 198, 138, 192, 198, 139, 33, 198, 34, - 34, 34, 34, 29, 140, 142, 198, 29, 29, 305, - 305, 29, 315, 305, 144, 305, 29, 307, 16, 327, - 29, 307, 307, 199, 199, 307, 328, 199, 330, 199, - 307, 29, 297, 297, 307, 331, 332, 297, 297, 337, - 153, 175, 305, 154, 297, 307, 305, 305, 9, 288, - 305, 28, 28, 28, 28, 305, 199, 288, 352, 305, - 199, 199, 8, 356, 199, 298, 298, 173, 367, 199, - 305, 172, 298, 199, 369, 200, 200, 3, 2, 200, - 157, 200, 263, nil, 199, 288, 288, 288, 288, 288, - 288, nil, 288, 288, nil, nil, nil, 200, 298, 288, - nil, nil, 298, 298, nil, nil, 298, nil, 200, nil, - nil, 298, 200, 200, nil, 298, 200, 4, 4, 4, - 4, 200, 200, 39, 39, 200, 298, 39, 200, 39, - 293, 293, 293, 293, 293, 293, 200, 293, 293, nil, - 283, 283, 283, 283, 293, 39, nil, 283, 283, 201, - 201, nil, nil, 201, 283, 201, 39, nil, nil, nil, - 39, 39, nil, nil, 39, nil, nil, nil, nil, 39, - 39, 201, nil, 39, nil, nil, 39, nil, nil, 46, - 46, nil, 201, 46, 39, 46, 201, 201, nil, nil, - 201, nil, nil, nil, nil, 201, 201, nil, nil, 201, - nil, 46, 201, nil, nil, 47, 47, nil, nil, 47, - 201, 47, 46, nil, nil, nil, 46, 46, nil, nil, - 46, nil, nil, nil, nil, 46, 46, 47, nil, 46, - 48, 48, 46, nil, 48, nil, 48, nil, 47, nil, - 46, nil, 47, 47, 49, 49, 47, nil, 49, nil, - nil, 47, 47, nil, nil, 47, nil, nil, 47, nil, - nil, nil, nil, 48, nil, nil, 47, 48, 48, 176, - 176, 48, nil, 176, nil, 176, 48, 49, nil, nil, - 48, 49, 49, nil, nil, 49, nil, nil, nil, nil, - 49, 48, nil, nil, 49, 203, 203, nil, nil, 203, - nil, 203, 176, nil, nil, 49, 176, 176, nil, nil, - 176, nil, nil, nil, nil, 176, nil, 203, nil, 176, - nil, 204, 204, nil, nil, 204, nil, 204, 203, nil, - 176, nil, 203, 203, nil, nil, 203, nil, nil, nil, - nil, 203, 203, 204, nil, 203, nil, nil, 203, nil, - nil, 205, 205, nil, 204, 205, 203, 205, 204, 204, - nil, nil, 204, nil, nil, nil, nil, 204, 204, nil, - nil, 204, nil, 205, 204, nil, nil, 100, 100, nil, - nil, 100, 204, 100, 205, nil, nil, nil, 205, 205, - nil, nil, 205, nil, nil, nil, nil, 205, 205, 100, - nil, 205, 63, 63, 205, nil, 63, nil, 63, nil, - 100, nil, 205, nil, 100, 100, nil, nil, 100, nil, - nil, nil, nil, 100, 100, nil, nil, 100, 208, 208, - 100, nil, 208, nil, 208, 63, nil, nil, 100, 63, - 63, nil, nil, 63, nil, nil, nil, nil, 63, nil, - 208, nil, 63, nil, 209, 209, nil, nil, 209, nil, - 209, 208, nil, 63, nil, 208, 208, nil, nil, 208, - nil, nil, 269, 269, 208, 208, 209, nil, 208, 276, - 276, 208, nil, 276, nil, 276, nil, 209, nil, 208, - nil, 209, 209, nil, nil, 209, nil, nil, nil, nil, - 209, 209, nil, nil, 209, 269, nil, 209, nil, 269, - 269, nil, 276, 269, nil, 209, 276, 276, 269, nil, - 276, nil, 269, nil, nil, 276, 256, 256, nil, 276, - 256, nil, 256, 269, nil, nil, nil, nil, nil, nil, - 276, nil, nil, nil, nil, 74, 74, nil, 256, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 256, - nil, nil, nil, 256, 256, nil, nil, 256, 74, nil, - 254, 254, 256, 256, nil, nil, 256, nil, 74, 256, - nil, nil, 74, 74, nil, nil, 74, 256, 75, 75, - 74, 74, 75, 254, 75, 74, nil, nil, nil, nil, - nil, nil, nil, 254, nil, nil, 74, 254, 254, nil, - 75, 254, nil, 248, 248, 254, 254, 248, nil, 248, - 254, 75, nil, 245, 245, 75, 75, nil, nil, 75, - nil, 254, nil, nil, 75, 75, nil, nil, 75, 244, - 244, 75, nil, nil, nil, nil, 248, nil, nil, 75, - 248, 248, nil, nil, 248, nil, 245, nil, nil, 248, - 245, 245, nil, 248, 245, nil, 225, 225, nil, 245, - 225, nil, 244, 245, 248, nil, 244, 244, nil, nil, - 244, nil, 82, 82, 245, 244, 82, nil, 82, 244, - nil, nil, 210, 210, nil, nil, 210, nil, 210, 225, - 244, nil, nil, 225, 225, nil, nil, 225, nil, nil, - nil, nil, 225, nil, 210, 82, 225, nil, nil, 82, - 82, nil, nil, 82, nil, 210, nil, 225, 82, 210, - 210, nil, 82, 210, nil, nil, nil, nil, 210, 210, - 213, 213, 210, 82, 213, 210, 213, 284, 284, 284, - 284, 284, 284, 210, 284, 284, nil, nil, nil, 102, - 102, 284, 213, 102, 102, 102, 230, 230, nil, nil, - 230, nil, 230, 213, nil, nil, nil, 213, 213, nil, - nil, 213, nil, nil, nil, nil, 213, 213, 214, 214, - 213, nil, 102, 213, nil, nil, 102, 102, nil, 230, - 102, 213, nil, 230, 230, 102, nil, 230, nil, 102, - nil, nil, 230, 228, 228, nil, 230, 228, nil, 228, - 102, 214, nil, nil, nil, 214, 214, 230, nil, 214, - nil, 94, 94, nil, 214, 94, nil, 94, 214, nil, - nil, nil, nil, nil, nil, nil, 228, nil, nil, 214, - 228, 228, nil, 94, 228, nil, nil, nil, nil, 228, - nil, 97, 97, 228, 94, 97, nil, 97, 94, 94, - nil, nil, 94, nil, 228, nil, nil, 94, 94, nil, - nil, 94, nil, 97, 94, nil, nil, 206, 206, nil, - nil, 206, 94, 206, 97, nil, nil, nil, 97, 97, - nil, nil, 97, nil, nil, nil, nil, 97, 97, 206, - nil, 97, nil, nil, 97, nil, nil, nil, nil, nil, - 206, nil, 97, nil, 206, 206, 111, nil, 206, nil, - nil, nil, nil, 206, 206, 111, 111, 206, nil, nil, - 206, nil, nil, nil, 111, 111, 111, 111, 206, nil, - 124, 124, nil, nil, nil, nil, nil, nil, nil, 124, - 124, 124, 124, nil, nil, nil, nil, nil, 111, 111, - nil, nil, 111, 111, 111, 111, 111, 111, nil, 111, - 111, nil, nil, 124, 124, nil, 111, 124, 124, 124, - 124, 124, 124, nil, 124, 124, 130, 130, nil, nil, - nil, 124, nil, nil, nil, 130, 130, 130, 130, nil, - nil, 131, 131, nil, nil, nil, nil, nil, nil, nil, - 131, 131, 131, 131, nil, nil, nil, nil, nil, 130, - 130, nil, nil, 130, 130, 130, 130, 130, 130, nil, - 130, 130, nil, nil, 131, 131, nil, 130, 131, 131, - 131, 131, 131, 131, nil, 131, 131, 287, 287, nil, - nil, nil, 131, nil, nil, nil, 287, 287, 287, 287, - nil, nil, 186, 186, nil, nil, nil, nil, nil, nil, - 186, 186, 186, 186, 186, nil, nil, nil, nil, nil, - nil, 287, nil, nil, 287, 287, 287, 287, 287, 287, - nil, 287, 287, nil, nil, 186, 186, nil, 287, 186, - 186, 186, 186, 186, 186, nil, 186, 186, 291, 291, - nil, nil, nil, 186, nil, nil, nil, 291, 291, 291, - 291, nil, nil, 19, 292, 19, 19, nil, 19, 19, - nil, 19, 292, 19, nil, 19, nil, 19, nil, nil, - 19, 19, nil, 289, nil, 291, 291, 291, 291, 291, - 291, 289, 291, 291, nil, nil, nil, nil, nil, 291, - 292, 292, 292, 292, 292, 292, nil, 292, 292, nil, - nil, 237, nil, nil, 292, nil, nil, nil, nil, 289, - 289, 289, 289, 289, 289, nil, 289, 289, nil, nil, - 372, nil, 237, 289, 237, 237, nil, 237, 237, nil, - 237, nil, 237, nil, 237, nil, 237, nil, nil, 237, - 237, 372, 378, 372, 372, nil, 372, 372, nil, 372, - nil, 372, nil, 372, nil, 372, nil, nil, 372, 372, - nil, 212, nil, 378, nil, 378, 378, nil, 378, 378, - nil, 378, nil, 378, nil, 378, nil, 378, nil, nil, - 378, 378, 212, 323, 212, 212, nil, 212, 212, nil, - 212, nil, 212, nil, 212, nil, 212, nil, nil, 212, - 212, nil, 374, nil, 323, nil, 323, 323, nil, 323, - 323, nil, 323, nil, 323, nil, 323, nil, 323, nil, - nil, 323, 323, 374, 380, 374, 374, nil, 374, 374, - nil, 374, nil, 374, nil, 374, nil, 374, nil, nil, - 374, 374, nil, 303, nil, 380, nil, 380, 380, nil, - 380, 380, nil, 380, nil, 380, nil, 380, nil, 380, - nil, nil, 380, 380, 303, 319, 303, 303, nil, 303, - 303, nil, 303, nil, 303, nil, 303, nil, 303, nil, - nil, 303, 303, nil, 362, nil, 319, nil, 319, 319, - nil, 319, 319, nil, 319, nil, 319, nil, 319, nil, - 319, nil, nil, 319, 319, 362, 217, 362, 362, nil, - 362, 362, nil, 362, nil, 362, nil, 362, nil, 362, - nil, nil, 362, 362, nil, 295, nil, 217, nil, 217, - 217, nil, 217, 217, nil, 217, nil, 217, nil, 217, - nil, 217, nil, nil, 217, 217, 295, nil, 295, 295, - nil, 295, 295, nil, 295, nil, 295, nil, 295, nil, - 295, nil, nil, 295, 295, 0, nil, 0, 0, nil, - 0, 0, nil, 0, nil, 0, nil, 0, nil, 0, - nil, nil, 0, 0 ] + 164, 164, 158, 154, 301, 27, 56, 27, 81, 214, + 285, 285, 301, 164, 164, 239, 293, 285, 18, 206, + 27, 213, 164, 164, 164, 164, 81, 206, 175, 175, + 194, 56, 175, 194, 175, 368, 368, 214, 214, 157, + 158, 293, 293, 158, 27, 154, 164, 164, 285, 144, + 164, 164, 164, 164, 164, 164, 18, 164, 164, 18, + 85, 175, 144, 158, 164, 175, 175, 272, 368, 175, + 83, 261, 368, 368, 175, 272, 368, 157, 175, 18, + 157, 368, 161, 161, 261, 368, 161, 216, 161, 175, + 1, 82, 356, 356, 1, 218, 368, 219, 203, 163, + 157, 1, 114, 272, 272, 272, 272, 272, 272, 203, + 272, 272, 163, 114, 203, 161, 122, 272, 114, 161, + 161, 122, 192, 161, 221, 356, 192, 192, 161, 356, + 356, 220, 161, 356, 290, 335, 335, 221, 356, 335, + 111, 335, 356, 161, 309, 290, 331, 331, 11, 309, + 290, 111, 11, 356, 329, 329, 111, 335, 329, 11, + 329, 48, 48, 103, 103, 48, 334, 48, 335, 334, + 103, 200, 335, 335, 262, 262, 335, 263, 263, 262, + 262, 335, 335, 48, 263, 335, 262, 329, 335, 224, + 280, 329, 329, 280, 48, 329, 335, 197, 48, 48, + 329, 103, 48, 227, 329, 295, 295, 48, 48, 87, + 229, 48, 307, 307, 48, 329, 307, 33, 307, 306, + 306, 33, 48, 306, 230, 306, 299, 299, 33, 33, + 225, 80, 232, 299, 225, 77, 46, 225, 295, 234, + 46, 225, 295, 295, 235, 307, 295, 46, 46, 307, + 307, 295, 306, 307, 75, 295, 306, 306, 307, 299, + 306, 212, 307, 299, 299, 306, 295, 299, 8, 306, + 23, 23, 299, 307, 23, 74, 299, 8, 8, 66, + 306, 249, 42, 252, 264, 264, 42, 299, 65, 166, + 166, 264, 23, 42, 42, 26, 26, 64, 89, 26, + 201, 26, 94, 23, 201, 201, 187, 23, 23, 169, + 101, 23, 102, 169, 169, 23, 23, 26, 105, 183, + 23, 53, 166, 52, 294, 294, 166, 166, 26, 50, + 166, 23, 26, 26, 166, 166, 26, 143, 106, 166, + 107, 26, 26, 29, 29, 26, 108, 29, 26, 29, + 166, 110, 279, 167, 167, 113, 26, 294, 115, 167, + 283, 294, 294, 281, 281, 294, 37, 211, 281, 281, + 294, 211, 211, 116, 294, 281, 29, 288, 170, 170, + 29, 29, 119, 32, 29, 294, 167, 121, 127, 29, + 167, 167, 297, 29, 167, 17, 287, 287, 133, 167, + 287, 170, 287, 167, 29, 3, 3, 3, 3, 304, + 13, 170, 12, 134, 167, 170, 170, 136, 320, 170, + 324, 172, 172, 170, 170, 172, 159, 172, 170, 287, + 140, 141, 155, 287, 287, 337, 342, 287, 346, 170, + 347, 349, 287, 172, 350, 351, 287, 45, 45, 5, + 357, 45, 142, 45, 172, 367, 147, 287, 172, 172, + 369, 2, 172, 4, 4, 4, 4, 172, 172, 45, + 146, 172, 379, 381, 172, nil, nil, 173, 173, nil, + 45, 173, 172, 173, 45, 45, nil, nil, 45, 31, + 31, 31, 31, 45, 45, nil, nil, 45, nil, 173, + 45, nil, nil, 47, 47, nil, nil, 47, 45, 47, + 173, nil, nil, nil, 173, 173, nil, nil, 173, 6, + 6, 6, 6, 173, 173, 47, nil, 173, nil, nil, + 173, nil, nil, 174, 174, nil, 47, 174, 173, 174, + 47, 47, nil, nil, 47, nil, nil, nil, nil, 47, + 47, nil, nil, 47, nil, 174, 47, nil, nil, 49, + 49, nil, nil, 49, 47, 49, 174, nil, nil, nil, + 174, 174, nil, nil, 174, nil, nil, 51, 51, 174, + 174, 51, nil, 174, 176, 176, 174, nil, 176, nil, + 176, nil, 49, nil, 174, nil, 49, 49, nil, nil, + 49, nil, nil, nil, nil, 49, 176, nil, nil, 49, + 51, nil, nil, nil, 51, 51, nil, 176, 51, nil, + 49, 176, 176, 51, nil, 176, nil, 51, nil, nil, + 176, 176, nil, nil, 176, 177, 177, 176, 51, 177, + nil, 177, nil, nil, nil, 176, nil, nil, nil, nil, + nil, nil, nil, nil, 112, 112, nil, 177, 112, nil, + 112, 259, 259, nil, nil, 259, nil, 259, 177, nil, + nil, nil, 177, 177, nil, nil, 177, nil, nil, 254, + 254, 177, 177, nil, nil, 177, nil, 112, 177, nil, + nil, 112, 112, nil, 259, 112, 177, nil, 259, 259, + 112, nil, 259, nil, 112, 70, 70, 259, nil, nil, + nil, 259, 254, nil, nil, 112, 254, 254, nil, nil, + 254, nil, 259, nil, nil, 254, 242, 242, 70, 254, + 242, nil, 242, nil, nil, nil, nil, nil, 70, nil, + 254, nil, 70, 70, nil, nil, 70, nil, 242, nil, + 70, 70, 71, 71, nil, 70, 71, nil, 71, 242, + nil, nil, nil, 242, 242, nil, 70, 242, nil, nil, + nil, nil, 242, 242, 71, nil, 242, 240, 240, 242, + nil, nil, nil, nil, nil, 71, nil, 242, nil, 71, + 71, nil, nil, 71, nil, nil, nil, nil, 71, 71, + 240, nil, 71, 178, 178, 71, nil, 178, nil, 178, + 240, nil, nil, 71, 240, 240, nil, nil, 240, nil, + nil, nil, 240, 240, nil, 178, nil, 240, 233, 233, + nil, nil, 233, nil, 233, nil, 178, nil, 240, nil, + 178, 178, 78, 78, 178, nil, 78, nil, 78, 178, + 178, nil, nil, 178, nil, nil, 178, nil, nil, nil, + nil, 233, nil, nil, 178, 233, 233, 231, 231, 233, + nil, 231, nil, 231, 233, 78, nil, nil, 233, 78, + 78, 228, 228, 78, nil, 228, nil, nil, 78, 233, + nil, nil, 78, nil, nil, nil, nil, nil, nil, nil, + 231, nil, nil, 78, 231, 231, nil, nil, 231, nil, + nil, 215, 215, 231, 228, nil, nil, 231, 228, 228, + nil, nil, 228, nil, nil, nil, nil, 228, 231, 179, + 179, 228, nil, 179, nil, 179, nil, nil, nil, nil, + nil, nil, 228, nil, 215, nil, nil, nil, 215, 215, + nil, 179, 215, nil, nil, nil, nil, 215, nil, 185, + 185, 215, 179, 185, nil, 185, 179, 179, nil, nil, + 179, nil, 215, nil, nil, 179, 179, nil, nil, 179, + nil, 185, 179, nil, nil, 181, 181, nil, nil, 181, + 179, 181, 185, nil, nil, nil, 185, 185, nil, nil, + 185, nil, nil, nil, nil, 185, 185, 181, nil, 185, + nil, nil, 185, nil, nil, 189, 189, nil, 181, 189, + 185, 189, 181, 181, nil, nil, 181, nil, nil, nil, + nil, 181, 181, nil, nil, 181, nil, 189, 181, nil, + nil, 90, 90, nil, nil, 90, 181, 90, 189, nil, + nil, nil, 189, 189, nil, nil, 189, nil, nil, nil, + nil, 189, 189, 90, nil, 189, nil, nil, 189, nil, + nil, 182, 182, nil, 90, 182, 189, 182, 90, 90, + nil, nil, 90, nil, nil, nil, nil, 90, 90, nil, + nil, 90, nil, 182, 90, nil, nil, 184, 184, nil, + nil, 184, 90, 184, 182, nil, nil, nil, 182, 182, + nil, nil, 182, nil, nil, nil, nil, 182, 182, 184, + nil, 182, nil, nil, 182, nil, nil, 95, 95, nil, + 184, 95, 182, 95, 184, 184, nil, nil, 184, nil, + nil, nil, nil, 184, 184, nil, nil, 184, nil, 95, + 184, nil, nil, 99, 99, nil, nil, 99, 184, 99, + 95, nil, nil, nil, 95, 95, nil, nil, 95, nil, + nil, nil, nil, 95, 95, 99, nil, 95, 100, 100, + 95, nil, 100, 100, 100, nil, 99, nil, 95, nil, + 99, 99, nil, nil, 99, nil, nil, nil, nil, 99, + 99, nil, nil, 99, 186, 186, 99, nil, 186, nil, + 186, 100, nil, nil, 99, 100, 100, nil, nil, 100, + nil, nil, nil, nil, 100, nil, 186, nil, 100, nil, + 180, 180, nil, nil, 180, nil, 180, 186, nil, 100, + nil, 186, 186, nil, nil, 186, nil, nil, nil, nil, + 186, 186, 180, nil, 186, nil, nil, 186, nil, nil, + nil, nil, nil, 180, nil, 186, nil, 180, 180, 91, + nil, 180, nil, nil, nil, nil, 180, 180, 91, 91, + 180, nil, nil, 180, nil, nil, nil, 91, 91, 91, + 91, 180, nil, 190, 190, nil, nil, nil, nil, nil, + nil, 190, 190, 190, 190, 190, nil, nil, nil, nil, + nil, 91, 91, nil, nil, 91, 91, 91, 91, 91, + 91, nil, 91, 91, nil, nil, 190, 190, nil, 91, + 190, 190, 190, 190, 190, 190, nil, 190, 190, 274, + 274, nil, nil, nil, 190, nil, nil, nil, 274, 274, + 274, 274, nil, nil, 132, 132, nil, nil, nil, nil, + nil, nil, nil, 132, 132, 132, 132, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 274, 274, 274, 274, + 274, 274, nil, 274, 274, nil, nil, 132, 132, nil, + 274, 132, 132, 132, 132, 132, 132, nil, 132, 132, + 131, 131, nil, nil, nil, 132, nil, nil, nil, 131, + 131, 131, 131, nil, nil, 270, 270, nil, nil, nil, + nil, nil, nil, nil, 270, 270, 270, 270, nil, nil, + nil, nil, nil, 131, 131, nil, nil, 131, 131, 131, + 131, 131, 131, nil, 131, 131, nil, nil, nil, 270, + nil, 131, 270, 270, 270, 270, 270, 270, nil, 270, + 270, 129, 129, nil, nil, nil, 270, nil, nil, nil, + 129, 129, 129, 129, nil, nil, nil, 269, nil, 276, + 276, 276, 276, 276, 276, 269, 276, 276, nil, nil, + nil, nil, nil, 276, 129, 129, 275, nil, 129, 129, + 129, 129, 129, 129, 275, 129, 129, nil, nil, nil, + nil, 271, 129, 269, 269, 269, 269, 269, 269, 271, + 269, 269, nil, nil, nil, nil, nil, 269, nil, nil, + nil, nil, 275, 275, 275, 275, 275, 275, nil, 275, + 275, 188, nil, nil, nil, nil, 275, 271, 271, 271, + 271, 271, 271, nil, 271, 271, nil, nil, nil, nil, + 238, 271, 188, nil, 188, 188, nil, 188, 188, nil, + 188, nil, 188, nil, 188, nil, 188, nil, nil, 188, + 188, 238, 311, 238, 238, nil, 238, 238, nil, 238, + nil, 238, nil, 238, nil, 238, nil, nil, 238, 238, + nil, 375, nil, 311, nil, 311, 311, nil, 311, 311, + nil, 311, nil, 311, nil, 311, nil, 311, nil, nil, + 311, 311, 375, 372, 375, 375, nil, 375, 375, nil, + 375, nil, 375, nil, 375, nil, 375, nil, nil, 375, + 375, nil, 362, nil, 372, nil, 372, 372, nil, 372, + 372, nil, 372, nil, 372, nil, 372, nil, 372, nil, + nil, 372, 372, 362, 217, 362, 362, nil, 362, 362, + nil, 362, nil, 362, nil, 362, nil, 362, nil, nil, + 362, 362, nil, nil, nil, 217, nil, 217, 217, nil, + 217, 217, nil, 217, nil, 217, nil, 217, nil, 217, + nil, nil, 217, 217, 0, nil, 0, 0, nil, 0, + 0, nil, 0, nil, 0, nil, 0, nil, 0, nil, + nil, 0, 0, 20, nil, 20, 20, nil, 20, 20, + nil, 20, nil, 20, nil, 20, nil, 20, nil, nil, + 20, 20, 278, nil, 278, 278, nil, 278, 278, nil, + 278, nil, 278, nil, 278, nil, 278, nil, nil, 278, + 278, 267, 267, 267, 267, 267, 267, nil, 267, 267, + 266, 266, 266, 266, nil, 267, nil, 266, 266, 268, + 268, 268, 268, nil, 266, nil, 268, 268, nil, nil, + nil, nil, nil, 268 ] racc_action_pointer = [ - 1795, 163, 443, 413, 433, nil, nil, 3, 434, 420, - nil, nil, 142, nil, nil, nil, 398, 26, nil, 1483, - nil, nil, 80, 271, nil, nil, 297, nil, 367, 348, - 166, nil, nil, 375, 315, 277, 337, nil, nil, 501, - nil, nil, nil, 221, nil, nil, 557, 583, 608, 622, - 315, 329, 348, nil, nil, 4, nil, nil, nil, nil, - nil, nil, 97, 780, 298, -9, 309, 302, 275, nil, - nil, 286, nil, nil, 923, 966, nil, 279, 269, nil, - 6, 248, 1060, nil, 239, 245, -3, 177, nil, nil, - 149, 137, nil, nil, 1209, 10, nil, 1239, nil, nil, - 755, 121, 1137, 225, nil, 233, 3, 299, 301, 304, - nil, 1298, nil, nil, 322, 325, nil, nil, nil, 323, - 205, 331, 144, nil, 1313, nil, nil, 351, nil, nil, - 1359, 1374, 352, 344, nil, nil, 328, nil, 350, 364, - 361, nil, 362, 79, 374, nil, nil, nil, nil, nil, - nil, nil, -9, 408, 386, nil, 2, 452, 30, nil, - 251, nil, nil, 84, nil, 50, nil, nil, nil, nil, - nil, 174, 439, 436, -14, 381, 647, nil, 114, nil, - -4, 57, 75, 197, 172, nil, 1435, nil, 225, nil, - nil, nil, 363, nil, nil, 213, 215, 241, 323, 401, - 453, 527, 32, 673, 699, 729, 1265, 265, 806, 832, - 1070, 249, 1612, 1118, 1166, 270, nil, 1757, 24, 24, - 91, 121, nil, nil, 142, 1044, 126, 161, 1191, 147, - 1144, 198, 233, 238, 273, nil, nil, 1552, nil, 39, - nil, nil, nil, 66, 1017, 1001, nil, nil, 991, nil, - 270, nil, 273, 279, 948, nil, 904, nil, nil, nil, - nil, nil, nil, 451, nil, nil, nil, nil, 283, 850, - nil, nil, -5, nil, 308, nil, 857, 8, nil, 226, - 198, 67, nil, 466, 1073, 86, 172, 1420, 411, 1515, - nil, 1481, 1496, 456, nil, 1776, -4, 356, 443, nil, - 145, nil, nil, 1694, nil, 387, nil, 362, 129, nil, - nil, nil, nil, nil, nil, 380, nil, nil, nil, 1716, - nil, nil, nil, 1634, nil, nil, nil, 376, 383, nil, - 385, 392, 393, nil, nil, nil, nil, 410, nil, nil, - nil, 153, nil, 183, nil, nil, nil, nil, nil, 51, - nil, 128, 430, nil, nil, 110, 435, nil, nil, nil, - nil, nil, 1735, nil, nil, nil, nil, 439, 59, 445, - nil, nil, 1571, nil, 1653, nil, nil, nil, 1593, nil, - 1675, nil, nil, nil ] + 1674, 54, 417, 341, 399, 434, 455, nil, 262, nil, + nil, 112, 404, 402, nil, nil, nil, 395, 16, nil, + 1693, nil, nil, 268, nil, nil, 293, -1, nil, 341, + nil, 425, 381, 181, nil, nil, nil, 342, nil, nil, + nil, nil, 246, nil, nil, 445, 200, 501, 159, 557, + 305, 575, 283, 321, nil, nil, -6, nil, nil, nil, + nil, nil, nil, nil, 291, 265, 273, nil, nil, nil, + 703, 750, nil, nil, 269, 242, nil, 212, 840, nil, + 208, 2, 68, 64, nil, 37, nil, 186, nil, 275, + 1039, 1261, nil, nil, 279, 1125, nil, nil, nil, 1151, + 1176, 287, 289, 161, nil, 295, 315, 317, 323, nil, + 343, 116, 652, 315, 78, 350, 361, nil, nil, 374, + nil, 379, 81, nil, nil, nil, nil, 382, nil, 1444, + nil, 1383, 1337, 391, 376, nil, 394, nil, nil, nil, + 389, 408, 440, 314, 38, nil, 447, 436, nil, nil, + nil, nil, nil, nil, -8, 420, nil, 37, 0, 418, + nil, 80, nil, 87, -4, nil, 287, 351, nil, 302, + 376, nil, 419, 475, 531, 26, 582, 633, 801, 927, + 1228, 983, 1069, 256, 1095, 957, 1202, 243, 1532, 1013, + 1276, nil, 115, nil, 21, nil, nil, 186, nil, nil, + 131, 254, nil, 74, nil, nil, 1, nil, nil, nil, + nil, 360, 249, 10, -13, 909, 85, 1655, 80, 82, + 106, 112, nil, nil, 181, 194, nil, 194, 879, 170, + 215, 865, 192, 826, 199, 235, nil, nil, 1551, 8, + 775, nil, 724, nil, nil, nil, nil, nil, nil, 270, + nil, nil, 259, nil, 677, nil, nil, nil, nil, 659, + nil, 59, 118, 116, 223, nil, 1716, 1707, 1725, 1459, + 1398, 1493, 49, nil, 1322, 1478, 1425, nil, 1712, 343, + 159, 307, nil, 353, nil, 8, nil, 394, 365, nil, + 110, nil, nil, -9, 322, 203, nil, 383, nil, 224, + nil, -8, nil, nil, 400, nil, 217, 210, nil, 109, + nil, 1573, nil, nil, nil, nil, nil, nil, nil, nil, + 406, nil, nil, nil, 411, nil, nil, nil, nil, 152, + nil, 135, nil, nil, 135, 133, nil, 427, nil, nil, + nil, nil, 427, nil, nil, nil, 415, 417, nil, 418, + 421, 422, nil, nil, nil, nil, 90, 442, nil, nil, + nil, nil, 1633, nil, nil, nil, nil, 446, 33, 451, + nil, nil, 1614, nil, nil, 1592, nil, nil, nil, 463, + nil, 464, nil, nil, nil ] racc_action_default = [ - -196, -233, -233, -50, -233, -8, -9, -233, -233, -22, - -10, -187, -188, -11, -185, -12, -233, -233, -13, -1, - -14, -2, -233, -186, -15, -3, -233, -16, -5, -233, - -233, -17, -6, -233, -18, -7, -196, -188, -186, -233, - -51, -26, -27, -233, -24, -25, -233, -233, -233, -85, - -92, -196, -233, -195, -193, -196, -189, -191, -192, -221, - -194, -4, -196, -233, -85, -196, -53, -231, -42, -174, - -43, -213, -117, -33, -233, -233, -44, -31, -74, -32, - -233, -36, -233, -122, -37, -233, -73, -38, -172, -72, - -39, -40, -173, -41, -233, -103, -111, -233, -132, -112, - -233, -104, -233, -108, -110, -105, -233, -114, -106, -113, - -109, -233, -125, -107, -233, -233, -49, -175, -176, -178, - -233, -233, -197, -198, -83, -19, -22, -186, -21, -23, - -82, -84, -233, -75, -86, -81, -70, -74, -76, -219, - -79, -68, -77, -73, -233, -171, -170, -80, -78, -90, - -91, -93, -233, -219, -196, 384, -233, -233, -233, -207, - -233, -57, -213, -196, -59, -233, -66, -65, -56, -73, - -95, -233, -219, -233, -233, -92, -233, -30, -233, -118, - -233, -233, -233, -233, -233, -142, -233, -149, -233, -216, - -229, -225, -233, -228, -224, -233, -233, -233, -233, -233, - -233, -233, -233, -233, -233, -233, -233, -233, -233, -233, - -233, -233, -233, -233, -233, -233, -20, -233, -206, -233, - -204, -233, -201, -230, -233, -71, -220, -233, -233, -85, - -233, -220, -233, -233, -233, -209, -190, -233, -208, -233, - -54, -62, -61, -233, -233, -233, -217, -218, -233, -124, - -233, -55, -219, -233, -233, -28, -233, -120, -119, -35, - -34, -168, -166, -233, -169, -160, -167, -161, -73, -233, - -123, -116, -233, -152, -218, -214, -233, -233, -222, -137, - -139, -138, -133, -140, -144, -141, -146, -151, -148, -145, - -134, -150, -147, -143, -135, -233, -128, -136, -233, -154, - -233, -158, -177, -233, -180, -233, -199, -233, -233, -200, - -45, -69, -87, -46, -88, -219, -89, -94, -48, -233, - -211, -210, -212, -233, -184, -58, -60, -97, -98, -63, - -102, -99, -100, -101, -64, -96, -47, -233, -232, -29, - -121, -233, -163, -219, -115, -215, -227, -226, -223, -128, - -127, -233, -233, -155, -153, -233, -233, -179, -205, -203, - -202, -67, -233, -182, -183, -52, -165, -218, -233, -233, - -126, -129, -233, -159, -233, -181, -164, -162, -233, -131, - -233, -157, -130, -156 ] + -197, -234, -51, -19, -8, -234, -234, -9, -234, -10, + -188, -189, -234, -23, -11, -186, -12, -234, -234, -13, + -1, -14, -2, -187, -15, -3, -234, -234, -16, -234, + -17, -6, -234, -234, -18, -7, -189, -197, -187, -52, + -27, -28, -234, -25, -26, -234, -234, -234, -234, -234, + -197, -86, -93, -234, -196, -194, -197, -190, -192, -193, + -222, -195, -4, -42, -232, -43, -214, -175, -118, -44, + -234, -234, -45, -34, -75, -32, -33, -234, -234, -123, + -37, -74, -38, -234, -73, -39, -173, -40, -174, -41, + -234, -234, -126, -108, -104, -234, -112, -133, -113, -234, + -234, -105, -109, -234, -111, -106, -115, -107, -114, -110, + -54, -197, -234, -86, -197, -234, -179, -176, -177, -234, + -50, -234, -198, -199, -24, -21, -23, -187, -22, -84, + -20, -83, -85, -234, -197, -79, -76, -87, -82, -75, + -71, -77, -220, -80, -74, -69, -78, -234, -172, -171, + -81, -91, -92, -94, -234, -220, 385, -234, -234, -234, + -208, -234, -31, -234, -234, -119, -234, -234, -96, -234, + -234, -143, -234, -234, -234, -234, -234, -234, -234, -234, + -234, -234, -234, -234, -234, -234, -234, -234, -234, -234, + -234, -150, -234, -217, -234, -230, -226, -234, -229, -225, + -93, -234, -214, -197, -58, -60, -234, -67, -57, -74, + -66, -234, -220, -234, -234, -234, -234, -234, -207, -205, + -234, -234, -202, -231, -234, -234, -210, -234, -72, -221, + -234, -234, -86, -234, -221, -234, -191, -209, -234, -234, + -234, -29, -234, -121, -120, -36, -35, -169, -167, -234, + -170, -161, -74, -168, -234, -162, -218, -219, -124, -234, + -117, -234, -138, -140, -139, -134, -141, -145, -142, -147, + -152, -149, -146, -135, -151, -148, -144, -136, -5, -234, + -129, -137, -153, -219, -215, -234, -223, -234, -220, -55, + -234, -63, -62, -234, -234, -234, -125, -234, -56, -234, + -155, -234, -159, -178, -234, -181, -234, -234, -200, -234, + -201, -234, -212, -213, -211, -46, -70, -88, -47, -89, + -220, -90, -95, -49, -234, -185, -233, -30, -122, -234, + -164, -220, -97, -116, -129, -234, -128, -234, -216, -227, + -224, -228, -234, -59, -61, -102, -98, -99, -64, -103, + -100, -101, -65, -48, -156, -154, -234, -234, -180, -206, + -204, -203, -234, -183, -68, -184, -166, -219, -234, -234, + -127, -130, -234, -53, -160, -234, -182, -165, -163, -234, + -132, -234, -158, -131, -157 ] racc_goto_table = [ - 22, 9, 68, 112, 53, 118, 61, 36, 91, 222, - 19, 267, 70, 93, 2, 227, 139, 191, 51, 22, - 9, 179, 77, 56, 73, 149, 21, 141, 133, 232, - 115, 172, 153, 2, 146, 263, 125, 116, 135, 148, - 147, 299, 129, 22, 126, 260, 160, 350, 250, 174, - 128, 171, 43, 68, 121, 329, 334, 298, 368, 91, - 258, 265, 123, 70, 93, 317, 343, 301, 136, 154, - 183, 119, 224, 178, 233, 73, 55, 123, 157, 66, - 238, 159, 120, 219, 221, 190, 325, 321, 195, 16, - 188, nil, nil, nil, nil, nil, nil, nil, 342, nil, - 370, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, 216, nil, nil, nil, nil, 260, 129, - 22, 126, 263, nil, nil, 353, nil, 128, 337, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 81, - nil, nil, nil, 53, nil, 53, nil, 243, nil, nil, - 149, 301, nil, nil, nil, nil, nil, 252, nil, nil, - 68, 261, 236, 68, nil, 138, 91, 146, nil, 91, - 70, 93, nil, 70, 93, nil, nil, nil, 166, nil, - 235, 166, 259, 272, nil, 73, nil, 302, 347, nil, - 81, 361, nil, 261, 290, 360, 315, 376, 294, 146, - nil, 312, 340, 311, 133, nil, 149, nil, 373, nil, - 146, nil, 22, 9, 135, 148, 147, 22, 9, 369, - nil, 263, 295, 327, 327, nil, 2, 303, nil, 146, - 146, 2, nil, 68, 333, 333, nil, 22, 9, 91, - 320, 88, nil, 70, 93, nil, nil, 323, 261, nil, - nil, 2, nil, nil, 146, 259, 190, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 88, nil, nil, - nil, nil, nil, nil, nil, 87, nil, 261, nil, 166, - nil, nil, 61, 146, nil, nil, nil, nil, nil, nil, - 61, nil, 88, nil, nil, 22, 9, 81, 262, nil, - 81, 142, nil, 22, 9, nil, nil, nil, nil, 2, - 61, nil, nil, nil, nil, nil, nil, 2, nil, 22, - 9, nil, nil, 22, 9, nil, 87, nil, 371, 362, - 262, nil, nil, 2, 261, nil, nil, 2, nil, nil, - 146, 138, nil, nil, nil, nil, nil, 261, nil, 61, - nil, nil, nil, 146, nil, 166, nil, nil, nil, nil, - 328, 328, 22, 9, 114, 61, nil, 61, nil, 84, - 81, nil, 22, 9, 22, 9, 2, 90, 22, 9, - 22, 9, 378, 132, 380, 262, 2, nil, 2, nil, - nil, nil, 2, nil, 2, 140, nil, nil, 170, 88, - 88, nil, 88, 145, nil, nil, nil, nil, 167, nil, - nil, 167, nil, nil, 262, nil, nil, 170, nil, nil, - 84, nil, nil, nil, nil, nil, nil, nil, 90, nil, - nil, nil, 88, 87, 266, nil, 87, 170, nil, nil, - nil, nil, nil, 88, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, 88, 88, nil, nil, 266, nil, nil, nil, - nil, 262, 88, nil, nil, nil, nil, 142, nil, nil, - nil, nil, nil, nil, 262, nil, nil, 88, nil, nil, - nil, nil, nil, nil, nil, nil, 331, 331, nil, nil, - nil, nil, nil, nil, nil, nil, 87, nil, nil, 167, - nil, 253, nil, nil, nil, nil, 88, nil, nil, nil, - nil, 266, nil, nil, nil, nil, nil, 84, 264, nil, - 84, nil, nil, nil, 282, 90, 145, nil, 90, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 266, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 264, nil, nil, 314, nil, 316, nil, 124, 145, nil, - nil, 140, nil, 88, 130, 131, nil, nil, nil, 145, - nil, nil, nil, 335, nil, 167, 88, nil, nil, nil, - 330, 330, nil, nil, nil, nil, nil, nil, 332, 332, - 84, nil, nil, 180, nil, nil, nil, 266, 90, nil, - nil, 346, nil, nil, nil, 264, nil, nil, nil, nil, - 266, nil, 185, 145, nil, 186, nil, nil, 187, nil, + 27, 13, 5, 37, 62, 255, 249, 20, 118, 196, + 92, 89, 142, 50, 155, 300, 69, 63, 222, 336, + 27, 13, 5, 165, 73, 75, 57, 279, 348, 352, + 246, 151, 145, 119, 343, 150, 121, 230, 65, 149, + 299, 22, 27, 126, 138, 135, 27, 126, 201, 134, + 235, 214, 120, 87, 302, 86, 304, 244, 89, 42, + 169, 128, 46, 69, 63, 128, 136, 251, 368, 331, + 322, 73, 163, 370, 212, 125, 124, 324, 123, 130, + 124, 148, 192, 86, 116, 65, 140, 224, 56, 159, + 227, 123, 330, 249, 211, 237, 220, 160, 221, 354, + 87, 110, 86, 115, 246, 314, 194, 297, 17, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 195, nil, + nil, nil, nil, 133, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 54, nil, nil, nil, 302, nil, + 293, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, 168, nil, 89, 149, nil, nil, 89, 69, + 63, nil, 288, 69, 63, 236, nil, 245, nil, nil, + nil, 73, 261, 82, 168, 226, nil, nil, nil, 151, + nil, 65, 247, 342, nil, 65, 168, nil, 27, 13, + 5, 339, 303, 320, 328, 374, 87, 148, 86, 86, + 87, 143, 86, 149, 80, 361, 377, 249, 317, 316, + nil, 379, 150, 151, 381, 364, 149, 27, 13, 5, + 82, 138, 135, nil, nil, nil, 369, 312, 89, nil, + 247, nil, 141, 69, 63, 239, nil, nil, 27, 13, + 5, 245, 149, 136, nil, 148, nil, 86, nil, 265, + nil, 80, nil, nil, nil, 65, nil, nil, 148, nil, + 86, 210, 62, nil, 210, nil, nil, nil, 85, 247, + 87, nil, 86, 54, 54, nil, nil, nil, 27, 13, + 5, nil, 149, 149, 148, nil, 86, 149, 345, 345, + nil, nil, 207, nil, nil, 207, 146, nil, nil, 273, + 195, nil, nil, 277, nil, 319, nil, 321, nil, 346, + 346, 27, 13, 5, 247, 85, 82, 250, 362, 371, + 82, nil, nil, nil, 351, 351, 86, 86, nil, 148, + nil, 86, nil, 332, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 149, nil, 62, 80, 248, nil, + nil, 80, nil, 210, nil, nil, 149, nil, nil, nil, + nil, 341, 27, 13, 5, 250, nil, nil, nil, nil, + nil, 247, 27, 13, 5, 27, 13, 5, 143, nil, + 359, 360, nil, 247, 207, nil, 148, nil, 86, nil, + 82, nil, 129, nil, 131, 132, 248, nil, 148, nil, + 86, nil, nil, 366, 250, nil, nil, nil, nil, 141, + nil, 85, 253, nil, nil, 85, nil, nil, 164, nil, + nil, 80, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 248, nil, 171, nil, nil, + 210, nil, 190, nil, 349, 349, 191, nil, nil, 250, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 358, nil, 359, nil, 264, nil, nil, nil, nil, nil, - nil, nil, 145, nil, nil, nil, nil, nil, nil, nil, + 253, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, 207, nil, 146, nil, 347, 347, nil, nil, nil, + 248, nil, nil, nil, nil, 85, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 253, + nil, nil, nil, nil, nil, nil, 250, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 250, 262, + 263, 264, nil, 266, 267, 268, 269, 270, 271, 272, + nil, 274, 275, 276, nil, nil, 281, 248, nil, 350, + 350, nil, nil, nil, 253, nil, nil, nil, nil, 248, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, 366, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 264, nil, nil, nil, nil, nil, nil, nil, 145, - nil, nil, nil, nil, 264, nil, nil, nil, nil, nil, - nil, nil, 145, nil, 279, 280, 281, nil, 283, 284, - 285, 286, 287, 288, 289, nil, 291, 292, 293, nil, - nil, 297, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 164, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 180 ] + nil, 253, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 253 ] racc_goto_check = [ - 37, 21, 30, 62, 64, 72, 4, 32, 28, 82, - 2, 70, 31, 29, 52, 36, 35, 85, 32, 37, - 21, 60, 22, 78, 21, 53, 3, 47, 30, 36, - 37, 35, 38, 52, 28, 68, 19, 5, 31, 29, - 50, 66, 7, 37, 21, 23, 41, 63, 36, 41, - 5, 57, 20, 30, 74, 46, 46, 65, 58, 28, - 61, 69, 3, 31, 29, 56, 71, 68, 33, 74, - 57, 73, 34, 22, 75, 21, 76, 3, 77, 40, - 79, 3, 20, 80, 81, 30, 42, 83, 84, 1, - 57, nil, nil, nil, nil, nil, nil, nil, 70, nil, - 63, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, 19, nil, nil, nil, nil, 23, 7, - 37, 21, 68, nil, nil, 66, nil, 5, 36, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 24, - nil, nil, nil, 64, nil, 64, nil, 41, nil, nil, - 53, 68, nil, nil, nil, nil, nil, 38, nil, nil, - 30, 30, 78, 30, nil, 24, 28, 28, nil, 28, - 31, 29, nil, 31, 29, nil, nil, nil, 24, nil, - 3, 24, 21, 22, nil, 21, nil, 72, 85, nil, - 24, 36, nil, 30, 64, 82, 35, 70, 64, 28, - nil, 53, 60, 47, 30, nil, 53, nil, 68, nil, - 28, nil, 37, 21, 31, 29, 50, 37, 21, 36, - nil, 68, 2, 30, 30, nil, 52, 2, nil, 28, - 28, 52, nil, 30, 29, 29, nil, 37, 21, 28, - 32, 49, nil, 31, 29, nil, nil, 2, 30, nil, - nil, 52, nil, nil, 28, 21, 30, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, 49, nil, nil, - nil, nil, nil, nil, nil, 26, nil, 30, nil, 24, - nil, nil, 4, 28, nil, nil, nil, nil, nil, nil, - 4, nil, 49, nil, nil, 37, 21, 24, 24, nil, - 24, 26, nil, 37, 21, nil, nil, nil, nil, 52, - 4, nil, nil, nil, nil, nil, nil, 52, nil, 37, - 21, nil, nil, 37, 21, nil, 26, nil, 62, 2, - 24, nil, nil, 52, 30, nil, nil, 52, nil, nil, - 28, 24, nil, nil, nil, nil, nil, 30, nil, 4, - nil, nil, nil, 28, nil, 24, nil, nil, nil, nil, - 24, 24, 37, 21, 54, 4, nil, 4, nil, 25, - 24, nil, 37, 21, 37, 21, 52, 27, 37, 21, - 37, 21, 2, 54, 2, 24, 52, nil, 52, nil, - nil, nil, 52, nil, 52, 25, nil, nil, 54, 49, - 49, nil, 49, 27, nil, nil, nil, nil, 25, nil, - nil, 25, nil, nil, 24, nil, nil, 54, nil, nil, - 25, nil, nil, nil, nil, nil, nil, nil, 27, nil, - nil, nil, 49, 26, 26, nil, 26, 54, nil, nil, - nil, nil, nil, 49, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, 49, 49, nil, nil, 26, nil, nil, nil, - nil, 24, 49, nil, nil, nil, nil, 26, nil, nil, - nil, nil, nil, nil, 24, nil, nil, 49, nil, nil, - nil, nil, nil, nil, nil, nil, 26, 26, nil, nil, - nil, nil, nil, nil, nil, nil, 26, nil, nil, 25, - nil, 54, nil, nil, nil, nil, 49, nil, nil, nil, - nil, 26, nil, nil, nil, nil, nil, 25, 25, nil, - 25, nil, nil, nil, 54, 27, 27, nil, 27, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 26, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 25, nil, nil, 54, nil, 54, nil, 51, 27, nil, - nil, 25, nil, 49, 51, 51, nil, nil, nil, 27, - nil, nil, nil, 54, nil, 25, 49, nil, nil, nil, - 25, 25, nil, nil, nil, nil, nil, nil, 27, 27, - 25, nil, nil, 51, nil, nil, nil, 26, 27, nil, - nil, 54, nil, nil, nil, 25, nil, nil, nil, nil, - 26, nil, 51, 27, nil, 51, nil, nil, 51, nil, + 38, 22, 53, 33, 4, 71, 69, 2, 73, 86, + 63, 29, 36, 33, 39, 67, 32, 30, 83, 64, + 38, 22, 53, 61, 22, 23, 79, 5, 47, 47, + 24, 54, 48, 38, 43, 51, 75, 37, 31, 29, + 66, 3, 38, 22, 32, 30, 38, 22, 42, 75, + 37, 42, 6, 28, 69, 50, 5, 62, 29, 21, + 58, 6, 21, 32, 30, 6, 31, 70, 59, 72, + 57, 22, 23, 64, 36, 20, 8, 5, 3, 20, + 8, 28, 58, 50, 74, 31, 34, 76, 77, 78, + 35, 3, 71, 69, 58, 80, 81, 3, 82, 67, + 28, 41, 50, 55, 24, 84, 85, 37, 1, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 31, nil, + nil, nil, nil, 55, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 65, nil, nil, nil, 69, nil, + 42, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, 55, nil, 29, 29, nil, nil, 29, 32, + 30, nil, 39, 32, 30, 79, nil, 22, nil, nil, + nil, 22, 23, 26, 55, 3, nil, nil, nil, 54, + nil, 31, 31, 37, nil, 31, 55, nil, 38, 22, + 53, 86, 73, 36, 61, 69, 28, 28, 50, 50, + 28, 26, 50, 29, 25, 83, 71, 69, 54, 48, + nil, 5, 51, 54, 5, 37, 29, 38, 22, 53, + 26, 32, 30, nil, nil, nil, 37, 33, 29, nil, + 31, nil, 25, 32, 30, 55, nil, nil, 38, 22, + 53, 22, 29, 31, nil, 28, nil, 50, nil, 55, + nil, 25, nil, nil, nil, 31, nil, nil, 28, nil, + 50, 26, 4, nil, 26, nil, nil, nil, 27, 31, + 28, nil, 50, 65, 65, nil, nil, nil, 38, 22, + 53, nil, 29, 29, 28, nil, 50, 29, 30, 30, + nil, nil, 25, nil, nil, 25, 27, nil, nil, 65, + 31, nil, nil, 65, nil, 55, nil, 55, nil, 31, + 31, 38, 22, 53, 31, 27, 26, 26, 2, 63, + 26, nil, nil, nil, 28, 28, 50, 50, nil, 28, + nil, 50, nil, 55, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 29, nil, 4, 25, 25, nil, + nil, 25, nil, 26, nil, nil, 29, nil, nil, nil, + nil, 55, 38, 22, 53, 26, nil, nil, nil, nil, + nil, 31, 38, 22, 53, 38, 22, 53, 26, nil, + 55, 55, nil, 31, 25, nil, 28, nil, 50, nil, + 26, nil, 52, nil, 52, 52, 25, nil, 28, nil, + 50, nil, nil, 55, 26, nil, nil, nil, nil, 25, + nil, 27, 27, nil, nil, 27, nil, nil, 52, nil, + nil, 25, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 25, nil, 52, nil, nil, + 26, nil, 52, nil, 26, 26, 52, nil, nil, 26, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - 54, nil, 54, nil, 25, nil, nil, nil, nil, nil, - nil, nil, 27, nil, nil, nil, nil, nil, nil, nil, + 27, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, 25, nil, 27, nil, 25, 25, nil, nil, nil, + 25, nil, nil, nil, nil, 27, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 27, + nil, nil, nil, nil, nil, nil, 26, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, 26, 52, + 52, 52, nil, 52, 52, 52, 52, 52, 52, 52, + nil, 52, 52, 52, nil, nil, 52, 25, nil, 27, + 27, nil, nil, nil, 27, nil, nil, nil, nil, 25, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, 54, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, 25, nil, nil, nil, nil, nil, nil, nil, 27, - nil, nil, nil, nil, 25, nil, nil, nil, nil, nil, - nil, nil, 27, nil, 51, 51, 51, nil, 51, 51, - 51, 51, 51, 51, 51, nil, 51, 51, 51, nil, - nil, 51, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, 52, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 51 ] + nil, 27, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 27 ] racc_goto_pointer = [ - nil, 89, 10, 26, -13, 7, nil, -1, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, -7, - 48, 1, -1, -136, 116, 346, 252, 354, -15, -10, - -21, -11, 6, 19, -64, -33, -124, 0, -18, nil, - 57, -16, -153, nil, nil, nil, -189, -22, nil, 218, - -9, 528, 14, -25, 335, nil, -166, -12, -285, nil, - -54, -120, -23, -249, -13, -157, -173, nil, -147, -121, - -171, -203, -28, 38, 18, -80, 59, 23, 6, -78, - -39, -38, -113, -147, -18, -89, nil ] + nil, 108, 7, 41, -16, -161, 19, nil, 34, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + 33, 56, 1, 2, -136, 181, 150, 245, 30, -12, + -6, 15, -7, 2, 35, -50, -39, -105, 0, -38, + nil, 74, -63, -256, nil, nil, nil, -266, -19, nil, + 32, -16, 347, 2, -21, 74, nil, -164, -18, -263, + nil, -48, -107, -16, -261, 116, -175, -200, nil, -161, + -100, -162, -185, -24, 52, -1, -47, 70, 33, 8, + -63, -26, -24, -104, -120, 3, -94, nil ] racc_goto_default = [ - nil, nil, nil, 168, 25, 28, 32, 35, 5, 6, - 10, 13, 15, 18, 20, 24, 27, 31, 34, 4, - nil, 99, nil, 79, 101, 103, 105, 108, 109, 113, - 95, 96, 8, nil, nil, nil, nil, 85, nil, 30, - nil, nil, 161, 239, 164, 165, nil, nil, 144, 107, - 110, 111, 67, 134, 98, 150, 151, nil, 248, 104, - nil, nil, nil, nil, 69, nil, nil, 300, 80, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, 57, - nil, nil, nil, nil, nil, nil, 192 ] + nil, nil, 278, 208, 25, nil, 31, 35, 4, 7, + 9, 14, 16, 19, 21, 24, 28, 30, 34, 3, + 6, nil, 98, nil, 76, 101, 102, 105, 107, 108, + 93, 94, 96, 12, nil, nil, nil, nil, 83, nil, + 33, nil, nil, 204, 290, 205, 206, nil, nil, 147, + 106, 109, 91, 64, 137, 97, 152, 153, nil, 259, + 104, nil, nil, nil, nil, 67, nil, nil, 301, 77, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + 58, nil, nil, nil, nil, nil, nil, 197 ] racc_token_table = { false => 0, @@ -1083,9 +1040,10 @@ Racc_token_to_s_table = [ 'IN', '$start', 'program', -'statements', +'statements_and_declarations', 'nil', -'statement', +'statement_or_declaration', +'statements', 'resource', 'virtualresource', 'collection', @@ -1175,48 +1133,39 @@ Racc_debug_parser = false # reduce 0 omitted -module_eval <<'.,.,', 'grammar.ra', 46 - def _reduce_1( val, _values, result ) - if val[0] - # Make sure we always return an array. - if val[0].is_a?(AST::ASTArray) - if val[0].children.empty? - result = nil - else - result = val[0] - end - else - result = aryfy(val[0]) - end - else - result = nil - end - result - end -.,., + # reduce 1 omitted # reduce 2 omitted - # reduce 3 omitted +module_eval <<'.,.,', 'grammar.ra', 36 + def _reduce_3( val, _values, result ) + result = ast AST::ASTArray, :children => (val[0] ? [val[0]] : []) + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 62 +module_eval <<'.,.,', 'grammar.ra', 42 def _reduce_4( val, _values, result ) - if val[0] and val[1] - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[1]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[1]] - end - elsif obj = (val[0] || val[1]) - result = obj - else result = nil + if val[1] + val[0].push(val[1]) end + result = val[0] result end .,., - # reduce 5 omitted +module_eval <<'.,.,', 'grammar.ra', 54 + def _reduce_5( val, _values, result ) + val[0].each do |stmt| + if stmt.is_a?(AST::TopLevelConstruct) + error "Classes, definitions, and nodes may only appear at toplevel or inside other classes", \ + :line => stmt.context[:line], :file => stmt.context[:file] + end + end + result = val[0] + result + end +.,., # reduce 6 omitted @@ -1244,22 +1193,22 @@ module_eval <<'.,.,', 'grammar.ra', 62 # reduce 18 omitted -module_eval <<'.,.,', 'grammar.ra', 82 - def _reduce_19( val, _values, result ) - result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) + # reduce 19 omitted + +module_eval <<'.,.,', 'grammar.ra', 74 + def _reduce_20( val, _values, result ) + result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) result end .,., -module_eval <<'.,.,', 'grammar.ra', 85 - def _reduce_20( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 77 + def _reduce_21( val, _values, result ) result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context) result end .,., - # reduce 21 omitted - # reduce 22 omitted # reduce 23 omitted @@ -1272,80 +1221,81 @@ module_eval <<'.,.,', 'grammar.ra', 85 # reduce 27 omitted -module_eval <<'.,.,', 'grammar.ra', 98 - def _reduce_28( val, _values, result ) - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement - result - end -.,., + # reduce 28 omitted -module_eval <<'.,.,', 'grammar.ra', 106 +module_eval <<'.,.,', 'grammar.ra', 89 def _reduce_29( val, _values, result ) - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => val[2], + :ftype => :statement result end .,., -module_eval <<'.,.,', 'grammar.ra', 112 +module_eval <<'.,.,', 'grammar.ra', 96 def _reduce_30( val, _values, result ) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :statement + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => val[2], + :ftype => :statement result end .,., -module_eval <<'.,.,', 'grammar.ra', 120 +module_eval <<'.,.,', 'grammar.ra', 102 def _reduce_31( val, _values, result ) - args = aryfy(val[1]) - result = ast AST::Function, - :name => val[0][:value], - :line => val[0][:line], - :arguments => args, - :ftype => :statement + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => AST::ASTArray.new({}), + :ftype => :statement result end .,., - # reduce 32 omitted +module_eval <<'.,.,', 'grammar.ra', 109 + def _reduce_32( val, _values, result ) + result = ast AST::Function, + :name => val[0][:value], + :line => val[0][:line], + :arguments => val[1], + :ftype => :statement + result + end +.,., - # reduce 33 omitted +module_eval <<'.,.,', 'grammar.ra', 110 + def _reduce_33( val, _values, result ) + result = aryfy(val[0]) + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 128 +module_eval <<'.,.,', 'grammar.ra', 111 def _reduce_34( val, _values, result ) - result = aryfy(val[0], val[2]) - result.line = @lexer.line - result.file = @lexer.file + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 137 +module_eval <<'.,.,', 'grammar.ra', 116 def _reduce_35( val, _values, result ) - unless val[0].is_a?(AST::ASTArray) - val[0] = aryfy(val[0]) - end - val[0].push(val[2]) - result = val[0] result end .,., - # reduce 36 omitted +module_eval <<'.,.,', 'grammar.ra', 120 + def _reduce_36( val, _values, result ) + val[0].push(val[2]) + result = val[0] + result + end +.,., # reduce 37 omitted @@ -1361,223 +1311,198 @@ module_eval <<'.,.,', 'grammar.ra', 137 # reduce 43 omitted -module_eval <<'.,.,', 'grammar.ra', 151 - def _reduce_44( val, _values, result ) - result = ast AST::Name, :value => val[0][:value] - result - end -.,., + # reduce 44 omitted -module_eval <<'.,.,', 'grammar.ra', 173 +module_eval <<'.,.,', 'grammar.ra', 134 def _reduce_45( val, _values, result ) - @lexer.commentpop - array = val[2] - if array.instance_of?(AST::ResourceInstance) - array = [array] - end - result = ast AST::ASTArray - - # this iterates across each specified resourceinstance - array.each { |instance| - unless instance.instance_of?(AST::ResourceInstance) - raise Puppet::Dev, "Got something that isn't an instance" - end - # now, i need to somehow differentiate between those things with - # arrays in their names, and normal things - result.push ast(AST::Resource, - :type => val[0], - :title => instance[0], - :parameters => instance[1]) - } + result = ast AST::Name, :value => val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 176 +module_eval <<'.,.,', 'grammar.ra', 139 def _reduce_46( val, _values, result ) - # This is a deprecated syntax. - error "All resource specifications require names" + @lexer.commentpop + result = ast(AST::Resource, :type => val[0], :instances => val[2]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 180 +module_eval <<'.,.,', 'grammar.ra', 142 def _reduce_47( val, _values, result ) - # a defaults setting for a type - @lexer.commentpop - result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) + # This is a deprecated syntax. + error "All resource specifications require names" result end .,., -module_eval <<'.,.,', 'grammar.ra', 186 +module_eval <<'.,.,', 'grammar.ra', 146 def _reduce_48( val, _values, result ) - @lexer.commentpop - result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] + # a defaults setting for a type + @lexer.commentpop + result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 213 +module_eval <<'.,.,', 'grammar.ra', 152 def _reduce_49( val, _values, result ) - type = val[0] + @lexer.commentpop + result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2] + result + end +.,., - if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect without storeconfigs being set") - end +module_eval <<'.,.,', 'grammar.ra', 171 + def _reduce_50( val, _values, result ) + type = val[0] - if val[1].is_a? AST::ResourceDefaults - error "Defaults are not virtualizable" - end + if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect without storeconfigs being set") + end - method = type.to_s + "=" + error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults - # Just mark our resources as exported and pass them through. - if val[1].instance_of?(AST::ASTArray) - val[1].each do |obj| - obj.send(method, true) - end - else - val[1].send(method, true) - end + method = type.to_s + "=" - result = val[1] + # Just mark our resource as exported and pass it through. + val[1].send(method, true) + + result = val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 214 - def _reduce_50( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 172 + def _reduce_51( val, _values, result ) result = :virtual result end .,., -module_eval <<'.,.,', 'grammar.ra', 215 - def _reduce_51( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 173 + def _reduce_52( val, _values, result ) result = :exported result end .,., -module_eval <<'.,.,', 'grammar.ra', 240 - def _reduce_52( val, _values, result ) - @lexer.commentpop - if val[0] =~ /^[a-z]/ - Puppet.warning addcontext("Collection names must now be capitalized") - end - type = val[0].downcase - args = {:type => type} - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - args[:override] = val[3] - result = ast AST::Collection, args +module_eval <<'.,.,', 'grammar.ra', 196 + def _reduce_53( val, _values, result ) + @lexer.commentpop + Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/ + type = val[0].downcase + args = {:type => type} + + if val[1].is_a?(AST::CollExpr) + args[:query] = val[1] + args[:query].type = type + args[:form] = args[:query].form + else + args[:form] = val[1] + end + if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") + end + args[:override] = val[3] + result = ast AST::Collection, args result end .,., -module_eval <<'.,.,', 'grammar.ra', 259 - def _reduce_53( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 215 + def _reduce_54( val, _values, result ) if val[0] =~ /^[a-z]/ - Puppet.warning addcontext("Collection names must now be capitalized") - end - type = val[0].downcase - args = {:type => type } - - if val[1].is_a?(AST::CollExpr) - args[:query] = val[1] - args[:query].type = type - args[:form] = args[:query].form - else - args[:form] = val[1] - end - if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] - Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") - end - result = ast AST::Collection, args + Puppet.warning addcontext("Collection names must now be capitalized") + end + type = val[0].downcase + args = {:type => type } + + if val[1].is_a?(AST::CollExpr) + args[:query] = val[1] + args[:query].type = type + args[:form] = args[:query].form + else + args[:form] = val[1] + end + if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly] + Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored") + end + result = ast AST::Collection, args result end .,., -module_eval <<'.,.,', 'grammar.ra', 269 - def _reduce_54( val, _values, result ) - if val[1] - result = val[1] - result.form = :virtual - else - result = :virtual - end +module_eval <<'.,.,', 'grammar.ra', 225 + def _reduce_55( val, _values, result ) + if val[1] + result = val[1] + result.form = :virtual + else + result = :virtual + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 277 - def _reduce_55( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 233 + def _reduce_56( val, _values, result ) if val[1] - result = val[1] - result.form = :exported - else - result = :exported - end + result = val[1] + result.form = :exported + else + result = :exported + end result end .,., - # reduce 56 omitted - # reduce 57 omitted -module_eval <<'.,.,', 'grammar.ra', 285 - def _reduce_58( val, _values, result ) + # reduce 58 omitted + +module_eval <<'.,.,', 'grammar.ra', 241 + def _reduce_59( val, _values, result ) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2] result end .,., - # reduce 59 omitted + # reduce 60 omitted -module_eval <<'.,.,', 'grammar.ra', 291 - def _reduce_60( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 247 + def _reduce_61( val, _values, result ) result = val[1] result.parens = true result end .,., -module_eval <<'.,.,', 'grammar.ra', 292 - def _reduce_61( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 248 + def _reduce_62( val, _values, result ) result=val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 293 - def _reduce_62( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 249 + def _reduce_63( val, _values, result ) result=val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 300 - def _reduce_63( val, _values, result ) - result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] - #result = ast AST::CollExpr - #result.push *val +module_eval <<'.,.,', 'grammar.ra', 256 + def _reduce_64( val, _values, result ) + result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] + #result = ast AST::CollExpr + #result.push *val result end .,., -module_eval <<'.,.,', 'grammar.ra', 305 - def _reduce_64( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 261 + def _reduce_65( val, _values, result ) result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2] #result = ast AST::CollExpr #result.push *val @@ -1585,57 +1510,56 @@ module_eval <<'.,.,', 'grammar.ra', 305 end .,., - # reduce 65 omitted - # reduce 66 omitted -module_eval <<'.,.,', 'grammar.ra', 312 - def _reduce_67( val, _values, result ) - result = ast AST::ResourceInstance, :children => [val[0],val[2]] + # reduce 67 omitted + +module_eval <<'.,.,', 'grammar.ra', 268 + def _reduce_68( val, _values, result ) + result = ast AST::ResourceInstance, :title => val[0], :parameters => val[2] result end .,., - # reduce 68 omitted - -module_eval <<'.,.,', 'grammar.ra', 322 +module_eval <<'.,.,', 'grammar.ra', 269 def _reduce_69( val, _values, result ) - if val[0].instance_of?(AST::ResourceInstance) - result = ast AST::ASTArray, :children => [val[0],val[2]] - else - val[0].push val[2] - result = val[0] - end + result = aryfy(val[0]) result end .,., - # reduce 70 omitted - - # reduce 71 omitted - -module_eval <<'.,.,', 'grammar.ra', 329 - def _reduce_72( val, _values, result ) - result = ast AST::Undef, :value => :undef +module_eval <<'.,.,', 'grammar.ra', 274 + def _reduce_70( val, _values, result ) + val[0].push val[2] + result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 333 + # reduce 71 omitted + + # reduce 72 omitted + +module_eval <<'.,.,', 'grammar.ra', 281 def _reduce_73( val, _values, result ) - result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Undef, :value => :undef result end .,., -module_eval <<'.,.,', 'grammar.ra', 337 +module_eval <<'.,.,', 'grammar.ra', 285 def _reduce_74( val, _values, result ) - result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Name, :value => val[0][:value], :line => val[0][:line] result end .,., - # reduce 75 omitted +module_eval <<'.,.,', 'grammar.ra', 289 + def _reduce_75( val, _values, result ) + result = ast AST::Type, :value => val[0][:value], :line => val[0][:line] + result + end +.,., # reduce 76 omitted @@ -1649,118 +1573,109 @@ module_eval <<'.,.,', 'grammar.ra', 337 # reduce 81 omitted -module_eval <<'.,.,', 'grammar.ra', 354 - def _reduce_82( val, _values, result ) - if val[0][:value] =~ /::/ - raise Puppet::ParseError, "Cannot assign to variables in other namespaces" - end - # this is distinct from referencing a variable - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] - result - end -.,., + # reduce 82 omitted -module_eval <<'.,.,', 'grammar.ra', 357 +module_eval <<'.,.,', 'grammar.ra', 304 def _reduce_83( val, _values, result ) - result = ast AST::VarDef, :name => val[0], :value => val[2] + raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/ + # this is distinct from referencing a variable + variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 362 +module_eval <<'.,.,', 'grammar.ra', 307 def _reduce_84( val, _values, result ) - variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] - result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] + result = ast AST::VarDef, :name => val[0], :value => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 367 +module_eval <<'.,.,', 'grammar.ra', 312 def _reduce_85( val, _values, result ) - result = ast AST::ASTArray + variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line] + result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 367 +module_eval <<'.,.,', 'grammar.ra', 317 def _reduce_86( val, _values, result ) - result = val[0] + result = ast AST::ASTArray result end .,., -module_eval <<'.,.,', 'grammar.ra', 376 +module_eval <<'.,.,', 'grammar.ra', 317 def _reduce_87( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 380 +module_eval <<'.,.,', 'grammar.ra', 322 def _reduce_88( val, _values, result ) - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] + val[0].push(val[2]) + result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 385 +module_eval <<'.,.,', 'grammar.ra', 326 def _reduce_89( val, _values, result ) - result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], - :add => true + result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2] result end .,., - # reduce 90 omitted - - # reduce 91 omitted - -module_eval <<'.,.,', 'grammar.ra', 393 - def _reduce_92( val, _values, result ) - result = ast AST::ASTArray +module_eval <<'.,.,', 'grammar.ra', 331 + def _reduce_90( val, _values, result ) + result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2], + :add => true result end .,., -module_eval <<'.,.,', 'grammar.ra', 393 + # reduce 91 omitted + + # reduce 92 omitted + +module_eval <<'.,.,', 'grammar.ra', 339 def _reduce_93( val, _values, result ) - result = val[0] + result = ast AST::ASTArray result end .,., -module_eval <<'.,.,', 'grammar.ra', 402 +module_eval <<'.,.,', 'grammar.ra', 339 def _reduce_94( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., - # reduce 95 omitted +module_eval <<'.,.,', 'grammar.ra', 344 + def _reduce_95( val, _values, result ) + val[0].push(val[2]) + result = val[0] + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 411 +module_eval <<'.,.,', 'grammar.ra', 345 def _reduce_96( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - result = val[0].push(val[2]) - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., - # reduce 97 omitted +module_eval <<'.,.,', 'grammar.ra', 346 + def _reduce_97( val, _values, result ) + result = val[0].push(val[2]) + result + end +.,., # reduce 98 omitted @@ -1796,392 +1711,387 @@ module_eval <<'.,.,', 'grammar.ra', 411 # reduce 114 omitted -module_eval <<'.,.,', 'grammar.ra', 440 - def _reduce_115( val, _values, result ) - args = aryfy(val[2]) - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => args, - :ftype => :rvalue - result - end -.,., + # reduce 115 omitted -module_eval <<'.,.,', 'grammar.ra', 445 +module_eval <<'.,.,', 'grammar.ra', 375 def _reduce_116( val, _values, result ) - result = ast AST::Function, - :name => val[0][:value], :line => val[0][:line], - :arguments => AST::ASTArray.new({}), - :ftype => :rvalue + result = ast AST::Function, + :name => val[0][:value], :line => val[0][:line], + :arguments => val[2], + :ftype => :rvalue result end .,., -module_eval <<'.,.,', 'grammar.ra', 446 +module_eval <<'.,.,', 'grammar.ra', 380 def _reduce_117( val, _values, result ) - result = ast AST::String, :value => val[0][:value], :line => val[0][:line] + result = ast AST::Function, + :name => val[0][:value], :line => val[0][:line], + :arguments => AST::ASTArray.new({}), + :ftype => :rvalue result end .,., -module_eval <<'.,.,', 'grammar.ra', 447 +module_eval <<'.,.,', 'grammar.ra', 381 def _reduce_118( val, _values, result ) - result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] + result = ast AST::String, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 449 +module_eval <<'.,.,', 'grammar.ra', 382 def _reduce_119( val, _values, result ) - result = [val[0]] + val[1] + result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 451 +module_eval <<'.,.,', 'grammar.ra', 384 def _reduce_120( val, _values, result ) - result = [ast(AST::String,val[0])] + result = [val[0]] + val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 452 +module_eval <<'.,.,', 'grammar.ra', 386 def _reduce_121( val, _values, result ) - result = [ast(AST::String,val[0])] + val[1] + result = [ast(AST::String,val[0])] result end .,., -module_eval <<'.,.,', 'grammar.ra', 457 +module_eval <<'.,.,', 'grammar.ra', 387 def _reduce_122( val, _values, result ) - result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] + result = [ast(AST::String,val[0])] + val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 462 +module_eval <<'.,.,', 'grammar.ra', 392 def _reduce_123( val, _values, result ) - Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") - result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] + result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 464 +module_eval <<'.,.,', 'grammar.ra', 397 def _reduce_124( val, _values, result ) - result = ast AST::ResourceReference, :type => val[0], :title => val[2] + Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized") + result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 468 +module_eval <<'.,.,', 'grammar.ra', 399 def _reduce_125( val, _values, result ) - result = val[1] + result = ast AST::ResourceReference, :type => val[0], :title => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 482 +module_eval <<'.,.,', 'grammar.ra', 403 def _reduce_126( val, _values, result ) - @lexer.commentpop - args = { - :test => val[0], - :statements => val[2] - } + result = val[1] + result + end +.,., - if val[4] - args[:else] = val[4] - end +module_eval <<'.,.,', 'grammar.ra', 415 + def _reduce_127( val, _values, result ) + @lexer.commentpop + args = { + :test => val[0], + :statements => val[2] + } + + args[:else] = val[4] if val[4] - result = ast AST::IfStatement, args + result = ast AST::IfStatement, args result end .,., -module_eval <<'.,.,', 'grammar.ra', 495 - def _reduce_127( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 426 + def _reduce_128( val, _values, result ) @lexer.commentpop args = { - :test => val[0], - :statements => ast(AST::Nop) - } + :test => val[0], + :statements => ast(AST::Nop) + } - if val[3] - args[:else] = val[3] - end + args[:else] = val[3] if val[3] - result = ast AST::IfStatement, args + result = ast AST::IfStatement, args result end .,., - # reduce 128 omitted + # reduce 129 omitted -module_eval <<'.,.,', 'grammar.ra', 501 - def _reduce_129( val, _values, result ) - #@lexer.commentpop +module_eval <<'.,.,', 'grammar.ra', 431 + def _reduce_130( val, _values, result ) result = ast AST::Else, :statements => val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 505 - def _reduce_130( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 435 + def _reduce_131( val, _values, result ) @lexer.commentpop result = ast AST::Else, :statements => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 509 - def _reduce_131( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 439 + def _reduce_132( val, _values, result ) @lexer.commentpop result = ast AST::Else, :statements => ast(AST::Nop) result end .,., - # reduce 132 omitted + # reduce 133 omitted -module_eval <<'.,.,', 'grammar.ra', 526 - def _reduce_133( val, _values, result ) - result = ast AST::InOperator, :lval => val[0], :rval => val[2] - result - end -.,., - -module_eval <<'.,.,', 'grammar.ra', 529 +module_eval <<'.,.,', 'grammar.ra', 456 def _reduce_134( val, _values, result ) - result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::InOperator, :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 532 +module_eval <<'.,.,', 'grammar.ra', 459 def _reduce_135( val, _values, result ) result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 535 +module_eval <<'.,.,', 'grammar.ra', 462 def _reduce_136( val, _values, result ) - result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 538 +module_eval <<'.,.,', 'grammar.ra', 465 def _reduce_137( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 541 +module_eval <<'.,.,', 'grammar.ra', 468 def _reduce_138( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 544 +module_eval <<'.,.,', 'grammar.ra', 471 def _reduce_139( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 547 +module_eval <<'.,.,', 'grammar.ra', 474 def _reduce_140( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 550 +module_eval <<'.,.,', 'grammar.ra', 477 def _reduce_141( val, _values, result ) result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 553 +module_eval <<'.,.,', 'grammar.ra', 480 def _reduce_142( val, _values, result ) - result = ast AST::Minus, :value => val[1] + result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 556 +module_eval <<'.,.,', 'grammar.ra', 483 def _reduce_143( val, _values, result ) - result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::Minus, :value => val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 559 +module_eval <<'.,.,', 'grammar.ra', 486 def _reduce_144( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 562 +module_eval <<'.,.,', 'grammar.ra', 489 def _reduce_145( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 565 +module_eval <<'.,.,', 'grammar.ra', 492 def _reduce_146( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 568 +module_eval <<'.,.,', 'grammar.ra', 495 def _reduce_147( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 571 +module_eval <<'.,.,', 'grammar.ra', 498 def _reduce_148( val, _values, result ) result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 574 +module_eval <<'.,.,', 'grammar.ra', 501 def _reduce_149( val, _values, result ) - result = ast AST::Not, :value => val[1] + result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 577 +module_eval <<'.,.,', 'grammar.ra', 504 def _reduce_150( val, _values, result ) - result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] + result = ast AST::Not, :value => val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 580 +module_eval <<'.,.,', 'grammar.ra', 507 def _reduce_151( val, _values, result ) result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 583 +module_eval <<'.,.,', 'grammar.ra', 510 def _reduce_152( val, _values, result ) - result = val[1] + result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 592 +module_eval <<'.,.,', 'grammar.ra', 513 def _reduce_153( val, _values, result ) - @lexer.commentpop - options = val[3] - unless options.instance_of?(AST::ASTArray) - options = ast AST::ASTArray, :children => [val[3]] - end - result = ast AST::CaseStatement, :test => val[1], :options => options + result = val[1] result end .,., - # reduce 154 omitted +module_eval <<'.,.,', 'grammar.ra', 518 + def _reduce_154( val, _values, result ) + @lexer.commentpop + result = ast AST::CaseStatement, :test => val[1], :options => val[3] + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 602 +module_eval <<'.,.,', 'grammar.ra', 519 def _reduce_155( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push val[1] - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0], val[1]] - end + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 607 +module_eval <<'.,.,', 'grammar.ra', 524 def _reduce_156( val, _values, result ) - @lexer.commentpop - result = ast AST::CaseOpt, :value => val[0], :statements => val[3] + val[0].push val[1] + result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 613 +module_eval <<'.,.,', 'grammar.ra', 529 def _reduce_157( val, _values, result ) - @lexer.commentpop - result = ast(AST::CaseOpt, - :value => val[0], - :statements => ast(AST::ASTArray) - ) + @lexer.commentpop + result = ast AST::CaseOpt, :value => val[0], :statements => val[3] result end .,., - # reduce 158 omitted +module_eval <<'.,.,', 'grammar.ra', 538 + def _reduce_158( val, _values, result ) + @lexer.commentpop -module_eval <<'.,.,', 'grammar.ra', 623 + result = ast( + AST::CaseOpt, + :value => val[0], + + :statements => ast(AST::ASTArray) + ) + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 539 def _reduce_159( val, _values, result ) - if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + result = aryfy(val[0]) result end .,., -module_eval <<'.,.,', 'grammar.ra', 627 +module_eval <<'.,.,', 'grammar.ra', 544 def _reduce_160( val, _values, result ) - result = ast AST::Selector, :param => val[0], :values => val[2] + val[0].push(val[2]) + result = val[0] result end .,., - # reduce 161 omitted +module_eval <<'.,.,', 'grammar.ra', 548 + def _reduce_161( val, _values, result ) + result = ast AST::Selector, :param => val[0], :values => val[2] + result + end +.,., + + # reduce 162 omitted -module_eval <<'.,.,', 'grammar.ra', 633 - def _reduce_162( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 554 + def _reduce_163( val, _values, result ) @lexer.commentpop result = val[1] result end .,., - # reduce 163 omitted + # reduce 164 omitted -module_eval <<'.,.,', 'grammar.ra', 643 - def _reduce_164( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 564 + def _reduce_165( val, _values, result ) if val[0].instance_of?(AST::ASTArray) - val[0].push(val[2]) - result = val[0] - else - result = ast AST::ASTArray, :children => [val[0],val[2]] - end + val[0].push(val[2]) + result = val[0] + else + result = ast AST::ASTArray, :children => [val[0],val[2]] + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 647 - def _reduce_165( val, _values, result ) - result = ast AST::ResourceParam, :param => val[0], :value => val[2] +module_eval <<'.,.,', 'grammar.ra', 568 + def _reduce_166( val, _values, result ) + result = ast AST::ResourceParam, :param => val[0], :value => val[2] result end .,., - # reduce 166 omitted - # reduce 167 omitted # reduce 168 omitted @@ -2194,208 +2104,217 @@ module_eval <<'.,.,', 'grammar.ra', 647 # reduce 172 omitted -module_eval <<'.,.,', 'grammar.ra', 658 - def _reduce_173( val, _values, result ) + # reduce 173 omitted + +module_eval <<'.,.,', 'grammar.ra', 579 + def _reduce_174( val, _values, result ) result = ast AST::Default, :value => val[0][:value], :line => val[0][:line] result end .,., - # reduce 174 omitted + # reduce 175 omitted -module_eval <<'.,.,', 'grammar.ra', 661 - def _reduce_175( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 582 + def _reduce_176( val, _values, result ) result = [val[0][:value]] result end .,., - # reduce 176 omitted + # reduce 177 omitted -module_eval <<'.,.,', 'grammar.ra', 663 - def _reduce_177( val, _values, result ) - result = val[0] += val[2] - result - end -.,., - -module_eval <<'.,.,', 'grammar.ra', 672 +module_eval <<'.,.,', 'grammar.ra', 584 def _reduce_178( val, _values, result ) - val[1].each do |file| - import(file) - end - - result = AST::ASTArray.new(:children => []) + result = val[0] += val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 683 +module_eval <<'.,.,', 'grammar.ra', 593 def _reduce_179( val, _values, result ) - @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line] - @lexer.indefine = false - result = nil + val[1].each do |file| + import(file) + end -#} | DEFINE NAME argumentlist parent LBRACE RBRACE { + result = nil result end .,., -module_eval <<'.,.,', 'grammar.ra', 688 +module_eval <<'.,.,', 'grammar.ra', 605 def _reduce_180( val, _values, result ) - @lexer.commentpop - newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line] - @lexer.indefine = false - result = nil + @lexer.commentpop + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :code => val[4], + :line => val[0][:line])) + @lexer.indefine = false + +#} | DEFINE NAME argumentlist parent LBRACE RBRACE { result end .,., -module_eval <<'.,.,', 'grammar.ra', 697 +module_eval <<'.,.,', 'grammar.ra', 610 def _reduce_181( val, _values, result ) - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line] - result = nil + @lexer.commentpop + result = Puppet::Parser::AST::Definition.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :line => val[0][:line])) + @lexer.indefine = false result end .,., -module_eval <<'.,.,', 'grammar.ra', 703 +module_eval <<'.,.,', 'grammar.ra', 620 def _reduce_182( val, _values, result ) - @lexer.commentpop - # Our class gets defined in the parent namespace, not our own. - @lexer.namepop - newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line] - result = nil + @lexer.commentpop + # Our class gets defined in the parent namespace, not our own. + @lexer.namepop + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :code => val[5], :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 709 +module_eval <<'.,.,', 'grammar.ra', 627 def _reduce_183( val, _values, result ) - @lexer.commentpop - newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line] - result = nil + @lexer.commentpop + # Our class gets defined in the parent namespace, not our own. + @lexer.namepop + result = Puppet::Parser::AST::Hostclass.new(classname(val[1]), + ast_context(true).merge(:arguments => val[2], :parent => val[3], + :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 713 +module_eval <<'.,.,', 'grammar.ra', 634 def _reduce_184( val, _values, result ) - @lexer.commentpop - newnode val[1], :parent => val[2], :line => val[0][:line] - result = nil + @lexer.commentpop + result = Puppet::Parser::AST::Node.new(val[1], + ast_context(true).merge(:parent => val[2], :code => val[4], + :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 714 +module_eval <<'.,.,', 'grammar.ra', 637 def _reduce_185( val, _values, result ) - result = val[0][:value] + @lexer.commentpop + result = Puppet::Parser::AST::Node.new(val[1], ast_context(true).merge(:parent => val[2], :line => val[0][:line])) result end .,., -module_eval <<'.,.,', 'grammar.ra', 716 +module_eval <<'.,.,', 'grammar.ra', 638 def _reduce_186( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 717 +module_eval <<'.,.,', 'grammar.ra', 640 def _reduce_187( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 718 +module_eval <<'.,.,', 'grammar.ra', 641 def _reduce_188( val, _values, result ) - result = "class" + result = val[0][:value] result end .,., - # reduce 189 omitted +module_eval <<'.,.,', 'grammar.ra', 642 + def _reduce_189( val, _values, result ) + result = "class" + result + end +.,., -module_eval <<'.,.,', 'grammar.ra', 728 +module_eval <<'.,.,', 'grammar.ra', 649 def _reduce_190( val, _values, result ) - result = val[0] - result = [result] unless result.is_a?(Array) - result << val[2] + result = [result] result end .,., -module_eval <<'.,.,', 'grammar.ra', 732 +module_eval <<'.,.,', 'grammar.ra', 653 def _reduce_191( val, _values, result ) - result = ast AST::HostName, :value => val[0] + result = val[0] + result << val[2] result end .,., -module_eval <<'.,.,', 'grammar.ra', 733 +module_eval <<'.,.,', 'grammar.ra', 657 def _reduce_192( val, _values, result ) - result = val[0][:value] + result = ast AST::HostName, :value => val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 734 +module_eval <<'.,.,', 'grammar.ra', 658 def _reduce_193( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 735 +module_eval <<'.,.,', 'grammar.ra', 659 def _reduce_194( val, _values, result ) result = val[0][:value] result end .,., - # reduce 195 omitted - -module_eval <<'.,.,', 'grammar.ra', 741 - def _reduce_196( val, _values, result ) - result = nil +module_eval <<'.,.,', 'grammar.ra', 660 + def _reduce_195( val, _values, result ) + result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 745 + # reduce 196 omitted + +module_eval <<'.,.,', 'grammar.ra', 666 def _reduce_197( val, _values, result ) - result = ast AST::ASTArray, :children => [] + result = nil + result + end +.,., + +module_eval <<'.,.,', 'grammar.ra', 670 + def _reduce_198( val, _values, result ) + result = ast AST::ASTArray, :children => [] result end .,., - # reduce 198 omitted + # reduce 199 omitted -module_eval <<'.,.,', 'grammar.ra', 750 - def _reduce_199( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 675 + def _reduce_200( val, _values, result ) result = nil result end .,., -module_eval <<'.,.,', 'grammar.ra', 754 - def _reduce_200( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 679 + def _reduce_201( val, _values, result ) result = val[1] result = [result] unless result[0].is_a?(Array) result end .,., - # reduce 201 omitted + # reduce 202 omitted -module_eval <<'.,.,', 'grammar.ra', 761 - def _reduce_202( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 686 + def _reduce_203( val, _values, result ) result = val[0] result = [result] unless result[0].is_a?(Array) result << val[2] @@ -2403,189 +2322,181 @@ module_eval <<'.,.,', 'grammar.ra', 761 end .,., -module_eval <<'.,.,', 'grammar.ra', 766 - def _reduce_203( val, _values, result ) - Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") - result = [val[0][:value], val[2]] +module_eval <<'.,.,', 'grammar.ra', 691 + def _reduce_204( val, _values, result ) + Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") + result = [val[0][:value], val[2]] result end .,., -module_eval <<'.,.,', 'grammar.ra', 770 - def _reduce_204( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 695 + def _reduce_205( val, _values, result ) Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype") result = [val[0][:value]] result end .,., -module_eval <<'.,.,', 'grammar.ra', 772 - def _reduce_205( val, _values, result ) - result = [val[0][:value], val[2]] +module_eval <<'.,.,', 'grammar.ra', 697 + def _reduce_206( val, _values, result ) + result = [val[0][:value], val[2]] result end .,., -module_eval <<'.,.,', 'grammar.ra', 774 - def _reduce_206( val, _values, result ) - result = [val[0][:value]] +module_eval <<'.,.,', 'grammar.ra', 699 + def _reduce_207( val, _values, result ) + result = [val[0][:value]] result end .,., - # reduce 207 omitted + # reduce 208 omitted -module_eval <<'.,.,', 'grammar.ra', 779 - def _reduce_208( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 704 + def _reduce_209( val, _values, result ) result = val[1] result end .,., - # reduce 209 omitted + # reduce 210 omitted -module_eval <<'.,.,', 'grammar.ra', 784 - def _reduce_210( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 709 + def _reduce_211( val, _values, result ) result = val[1] result end .,., - # reduce 211 omitted - # reduce 212 omitted -module_eval <<'.,.,', 'grammar.ra', 790 - def _reduce_213( val, _values, result ) - result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] - result - end -.,., + # reduce 213 omitted -module_eval <<'.,.,', 'grammar.ra', 798 +module_eval <<'.,.,', 'grammar.ra', 715 def _reduce_214( val, _values, result ) - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end + result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line] result end .,., -module_eval <<'.,.,', 'grammar.ra', 805 +module_eval <<'.,.,', 'grammar.ra', 716 def _reduce_215( val, _values, result ) - if val[1].instance_of?(AST::ASTArray) - result = val[1] - else - result = ast AST::ASTArray, :children => [val[1]] - end + result = val[1] result end .,., -module_eval <<'.,.,', 'grammar.ra', 807 +module_eval <<'.,.,', 'grammar.ra', 717 def _reduce_216( val, _values, result ) - result = ast AST::ASTArray + result = val[1] result end .,., - # reduce 217 omitted +module_eval <<'.,.,', 'grammar.ra', 718 + def _reduce_217( val, _values, result ) + result = ast AST::ASTArray + result + end +.,., # reduce 218 omitted # reduce 219 omitted -module_eval <<'.,.,', 'grammar.ra', 812 - def _reduce_220( val, _values, result ) + # reduce 220 omitted + +module_eval <<'.,.,', 'grammar.ra', 724 + def _reduce_221( val, _values, result ) result = nil result end .,., -module_eval <<'.,.,', 'grammar.ra', 817 - def _reduce_221( val, _values, result ) - result = ast AST::Regex, :value => val[0][:value] +module_eval <<'.,.,', 'grammar.ra', 729 + def _reduce_222( val, _values, result ) + result = ast AST::Regex, :value => val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 825 - def _reduce_222( val, _values, result ) - if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end +module_eval <<'.,.,', 'grammar.ra', 737 + def _reduce_223( val, _values, result ) + if val[1].instance_of?(AST::ASTHash) + result = val[1] + else + result = ast AST::ASTHash, { :value => val[1] } + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 832 - def _reduce_223( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 744 + def _reduce_224( val, _values, result ) if val[1].instance_of?(AST::ASTHash) - result = val[1] - else - result = ast AST::ASTHash, { :value => val[1] } - end + result = val[1] + else + result = ast AST::ASTHash, { :value => val[1] } + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 834 - def _reduce_224( val, _values, result ) - result = ast AST::ASTHash +module_eval <<'.,.,', 'grammar.ra', 746 + def _reduce_225( val, _values, result ) + result = ast AST::ASTHash result end .,., - # reduce 225 omitted + # reduce 226 omitted -module_eval <<'.,.,', 'grammar.ra', 844 - def _reduce_226( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 756 + def _reduce_227( val, _values, result ) if val[0].instance_of?(AST::ASTHash) - result = val[0].merge(val[2]) - else - result = ast AST::ASTHash, :value => val[0] - result.merge(val[2]) - end + result = val[0].merge(val[2]) + else + result = ast AST::ASTHash, :value => val[0] + result.merge(val[2]) + end result end .,., -module_eval <<'.,.,', 'grammar.ra', 848 - def _reduce_227( val, _values, result ) - result = ast AST::ASTHash, { :value => { val[0] => val[2] } } +module_eval <<'.,.,', 'grammar.ra', 760 + def _reduce_228( val, _values, result ) + result = ast AST::ASTHash, { :value => { val[0] => val[2] } } result end .,., -module_eval <<'.,.,', 'grammar.ra', 849 - def _reduce_228( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 761 + def _reduce_229( val, _values, result ) result = val[0][:value] result end .,., -module_eval <<'.,.,', 'grammar.ra', 850 - def _reduce_229( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 762 + def _reduce_230( val, _values, result ) result = val[0] result end .,., -module_eval <<'.,.,', 'grammar.ra', 855 - def _reduce_230( val, _values, result ) - result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] +module_eval <<'.,.,', 'grammar.ra', 767 + def _reduce_231( val, _values, result ) + result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2] result end .,., - # reduce 231 omitted + # reduce 232 omitted -module_eval <<'.,.,', 'grammar.ra', 860 - def _reduce_232( val, _values, result ) +module_eval <<'.,.,', 'grammar.ra', 772 + def _reduce_233( val, _values, result ) result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2] result end diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index c0fd37178..746aa0f90 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -29,29 +29,20 @@ class Puppet::Parser::Parser message end - # Create an AST array out of all of the args - def aryfy(*args) - if args[0].instance_of?(AST::ASTArray) - result = args.shift - args.each { |arg| - result.push arg - } - else - result = ast AST::ASTArray, :children => args - end - - result + # Create an AST array containing a single element + def aryfy(arg) + ast AST::ASTArray, :children => [arg] end # Create an AST object, and automatically add the file and line information if # available. def ast(klass, hash = {}) - klass.new ast_context(klass.use_docs).merge(hash) + klass.new ast_context(klass.use_docs, hash[:line]).merge(hash) end - def ast_context(include_docs = false) + def ast_context(include_docs = false, ast_line = nil) result = { - :line => lexer.line, + :line => ast_line || lexer.line, :file => lexer.file } result[:doc] = lexer.getcomment(result[:line]) if include_docs @@ -68,13 +59,13 @@ class Puppet::Parser::Parser end # Raise a Parse error. - def error(message) + def error(message, options = {}) if brace = @lexer.expected message += "; expected '%s'" end except = Puppet::ParseError.new(message) - except.line = @lexer.line - except.file = @lexer.file if @lexer.file + except.line = options[:line] || @lexer.line + except.file = options[:file] || @lexer.file raise except end @@ -103,15 +94,15 @@ class Puppet::Parser::Parser end def find_hostclass(namespace, name) - known_resource_types.find_or_load(namespace, name, :hostclass) + known_resource_types.find_hostclass(namespace, name) end def find_definition(namespace, name) - known_resource_types.find_or_load(namespace, name, :definition) + known_resource_types.find_definition(namespace, name) end def import(file) - known_resource_types.loader.import_if_possible(file, @lexer.file) + known_resource_types.loader.import(file, @lexer.file) end def initialize(env) @@ -133,26 +124,6 @@ class Puppet::Parser::Parser return ns, n end - # Create a new class, or merge with an existing class. - def newclass(name, options = {}) - known_resource_types.add Puppet::Resource::Type.new(:hostclass, name, ast_context(true).merge(options)) - end - - # Create a new definition. - def newdefine(name, options = {}) - known_resource_types.add Puppet::Resource::Type.new(:definition, name, ast_context(true).merge(options)) - end - - # Create a new node. Nodes are special, because they're stored in a global - # table, not according to namespaces. - def newnode(names, options = {}) - names = [names] unless names.instance_of?(Array) - context = ast_context(true) - names.collect do |name| - known_resource_types.add(Puppet::Resource::Type.new(:node, name, context.merge(options))) - end - end - def on_error(token,value,stack) if token == 0 # denotes end of file value = 'end of file' @@ -174,48 +145,54 @@ class Puppet::Parser::Parser # how should I do error handling here? def parse(string = nil) - return parse_ruby_file if self.file =~ /\.rb$/ - self.string = string if string - begin - @yydebug = false - main = yyparse(@lexer,:scan) - rescue Racc::ParseError => except - error = Puppet::ParseError.new(except) - error.line = @lexer.line - error.file = @lexer.file - error.set_backtrace except.backtrace - raise error - rescue Puppet::ParseError => except - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue Puppet::Error => except - # and this is a framework error - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue Puppet::DevError => except - except.line ||= @lexer.line - except.file ||= @lexer.file - raise except - rescue => except - error = Puppet::DevError.new(except.message) - error.line = @lexer.line - error.file = @lexer.file - error.set_backtrace except.backtrace - raise error - end - if main - # Store the results as the top-level class. - newclass("", :code => main) + if self.file =~ /\.rb$/ + main = parse_ruby_file + else + self.string = string if string + begin + @yydebug = false + main = yyparse(@lexer,:scan) + rescue Racc::ParseError => except + error = Puppet::ParseError.new(except) + error.line = @lexer.line + error.file = @lexer.file + error.set_backtrace except.backtrace + raise error + rescue Puppet::ParseError => except + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue Puppet::Error => except + # and this is a framework error + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue Puppet::DevError => except + except.line ||= @lexer.line + except.file ||= @lexer.file + raise except + rescue => except + error = Puppet::DevError.new(except.message) + error.line = @lexer.line + error.file = @lexer.file + error.set_backtrace except.backtrace + raise error + end end - return known_resource_types + # Store the results as the top-level class. + return Puppet::Parser::AST::Hostclass.new('', :code => main) ensure @lexer.clear end def parse_ruby_file - require self.file + # Execute the contents of the file inside its own "main" object so + # that it can call methods in the resource type API. + main_object = Puppet::DSL::ResourceTypeAPI.new + main_object.instance_eval(File.read(self.file)) + + # Then extract any types that were created. + Puppet::Parser::AST::ASTArray.new :children => main_object.instance_eval { @__created_ast_objects__ } end def string=(string) diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index c956a1106..c007d4dbe 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -64,6 +64,8 @@ class Puppet::Parser::Resource < Puppet::Resource # Retrieve the associated definition and evaluate it. def evaluate + return if evaluated? + @evaluated = true if klass = resource_type and ! builtin_type? finish return klass.evaluate_code(self) @@ -72,8 +74,6 @@ class Puppet::Parser::Resource < Puppet::Resource else self.fail "Cannot find definition #{type}" end - ensure - @evaluated = true end # Mark this resource as both exported and virtual, @@ -94,6 +94,7 @@ class Puppet::Parser::Resource < Puppet::Resource @finished = true add_defaults add_metaparams + add_scope_tags validate end @@ -103,9 +104,9 @@ class Puppet::Parser::Resource < Puppet::Resource end def initialize(*args) + raise ArgumentError, "Resources require a scope" unless args.last[:scope] super - raise ArgumentError, "Resources require a scope" unless scope @source ||= scope.source end @@ -141,10 +142,6 @@ class Puppet::Parser::Resource < Puppet::Resource self[:name] || self.title end - def namespaces - scope.namespaces - end - # A temporary occasion, until I get paths in the scopes figured out. def path to_s @@ -264,6 +261,12 @@ class Puppet::Parser::Resource < Puppet::Resource end end + def add_scope_tags + if scope_resource = scope.resource + tag(*scope_resource.tags) + end + end + # Accept a parameter from an override. def override_parameter(param) # This can happen if the override is defining a new parameter, rather diff --git a/lib/puppet/parser/resource/param.rb b/lib/puppet/parser/resource/param.rb index af2d98fe8..c28322337 100644 --- a/lib/puppet/parser/resource/param.rb +++ b/lib/puppet/parser/resource/param.rb @@ -13,7 +13,7 @@ class Puppet::Parser::Resource::Param def initialize(hash) set_options(hash) - requiredopts(:name, :value, :source) + requiredopts(:name, :value) @name = symbolize(@name) end diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index ae0f9ea4a..24f1d01f7 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -474,6 +474,41 @@ class Puppet::Parser::Scope end end + def find_resource_type(type) + # It still works fine without the type == 'class' short-cut, but it is a lot slower. + return nil if ["class", "node"].include? type.to_s.downcase + find_builtin_resource_type(type) || find_defined_resource_type(type) + end + + def find_builtin_resource_type(type) + Puppet::Type.type(type.to_s.downcase.to_sym) + end + + def find_defined_resource_type(type) + environment.known_resource_types.find_definition(namespaces, type.to_s.downcase) + end + + def resolve_type_and_titles(type, titles) + raise ArgumentError, "titles must be an array" unless titles.is_a?(Array) + + case type.downcase + when "class" + # resolve the titles + titles = titles.collect do |a_title| + hostclass = find_hostclass(a_title) + hostclass ? hostclass.name : a_title + end + when "node" + # no-op + else + # resolve the type + resource_type = find_resource_type(type) + type = resource_type.name if resource_type + end + + return [type, titles] + end + private def extend_with_functions_module diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 73a4ad8aa..6864aa1a9 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -1,6 +1,7 @@ # A simple wrapper for templates, so they don't have full access to # the scope objects. require 'puppet/parser/files' +require 'erb' class Puppet::Parser::TemplateWrapper attr_writer :scope diff --git a/lib/puppet/parser/type_loader.rb b/lib/puppet/parser/type_loader.rb index 35ad49593..140c9f2ca 100644 --- a/lib/puppet/parser/type_loader.rb +++ b/lib/puppet/parser/type_loader.rb @@ -3,25 +3,56 @@ require 'puppet/node/environment' class Puppet::Parser::TypeLoader include Puppet::Node::Environment::Helper - class Helper < Hash + # Helper class that makes sure we don't try to import the same file + # more than once from either the same thread or different threads. + class Helper include MonitorMixin - def done_with(item) - synchronize do - delete(item)[:busy].signal if self.has_key?(item) and self[item][:loader] == Thread.current - end + def initialize + super + # These hashes are indexed by filename + @state = {} # :doing or :done + @thread = {} # if :doing, thread that's doing the parsing + @cond_var = {} # if :doing, condition var that will be signaled when done. end - def owner_of(item) - synchronize do - if !self.has_key? item - self[item] = { :loader => Thread.current, :busy => self.new_cond} - :nobody - elsif self[item][:loader] == Thread.current - :this_thread + + # Execute the supplied block exactly once per file, no matter how + # many threads have asked for it to run. If another thread is + # already executing it, wait for it to finish. If this thread is + # already executing it, return immediately without executing the + # block. + # + # Note: the reason for returning immediately if this thread is + # already executing the block is to handle the case of a circular + # import--when this happens, we attempt to recursively re-parse a + # file that we are already in the process of parsing. To prevent + # an infinite regress we need to simply do nothing when the + # recursive import is attempted. + def do_once(file) + need_to_execute = synchronize do + case @state[file] + when :doing + if @thread[file] != Thread.current + @cond_var[file].wait + end + false + when :done + false else - flag = self[item][:busy] - flag.wait - flag.signal - :another_thread + @state[file] = :doing + @thread[file] = Thread.current + @cond_var[file] = new_cond + true + end + end + if need_to_execute + begin + yield + ensure + synchronize do + @state[file] = :done + @thread.delete(file) + @cond_var.delete(file).broadcast + end end end end @@ -47,21 +78,18 @@ class Puppet::Parser::TypeLoader raise Puppet::ImportError.new("No file(s) found for import of '#{pat}'") end + loaded_asts = [] files.each do |file| unless file =~ /^#{File::SEPARATOR}/ file = File.join(dir, file) end - unless imported? file - @imported[file] = true - parse_file(file) + @loading_helper.do_once(file) do + loaded_asts << parse_file(file) end end - - modname - end - - def imported?(file) - @imported.has_key?(file) + loaded_asts.inject([]) do |loaded_types, ast| + loaded_types + known_resource_types.import_ast(ast, modname) + end end def known_resource_types @@ -70,77 +98,48 @@ class Puppet::Parser::TypeLoader def initialize(env) self.environment = env - @loaded = {} - @loading = Helper.new - - @imported = {} + @loading_helper = Helper.new end - def load_until(namespaces, name) - return nil if name == "" # special-case main. - name2files(namespaces, name).each do |filename| - modname = begin - import_if_possible(filename) + # Try to load the object with the given fully qualified name. + def try_load_fqname(type, fqname) + return nil if fqname == "" # special-case main. + name2files(fqname).each do |filename| + begin + imported_types = import(filename) + if result = imported_types.find { |t| t.type == type and t.name == fqname } + Puppet.debug "Automatically imported #{fqname} from #{filename} into #{environment}" + return result + end rescue Puppet::ImportError => detail # We couldn't load the item # I'm not convienced we should just drop these errors, but this # preserves existing behaviours. - nil - end - if result = yield(filename) - Puppet.info "Automatically imported #{name} from #{filename} into #{environment}" - result.module_name = modname if modname and result.respond_to?(:module_name=) - return result end end - nil - end - - def loaded?(name) - @loaded.include?(name) - end - - def name2files(namespaces, name) - return [name.sub(/^::/, '').gsub("::", File::SEPARATOR)] if name =~ /^::/ - - result = namespaces.inject([]) do |names_to_try, namespace| - fullname = (namespace + "::#{name}").sub(/^::/, '') - - # Try to load the module init file if we're a qualified name - names_to_try << fullname.split("::")[0] if fullname.include?("::") - - # Then the fully qualified name - names_to_try << fullname - end - - # Otherwise try to load the bare name on its own. This - # is appropriate if the class we're looking for is in a - # module that's different from our namespace. - result << name - result.uniq.collect { |f| f.gsub("::", File::SEPARATOR) } + # Nothing found. + return nil end def parse_file(file) Puppet.debug("importing '#{file}' in environment #{environment}") parser = Puppet::Parser::Parser.new(environment) parser.file = file - parser.parse + return parser.parse end - # Utility method factored out of load for handling thread-safety. - # This isn't tested in the specs, because that's basically impossible. - def import_if_possible(file, current_file = nil) - @loaded[file] || begin - case @loading.owner_of(file) - when :this_thread - nil - when :another_thread - import_if_possible(file,current_file) - when :nobody - @loaded[file] = import(file,current_file) - end - ensure - @loading.done_with(file) + private + + # Return a list of all file basenames that should be tried in order + # to load the object with the given fully qualified name. + def name2files(fqname) + result = [] + ary = fqname.split("::") + while ary.length > 0 + result << ary.join(File::SEPARATOR) + ary.pop end + return result end + end diff --git a/lib/puppet/property.rb b/lib/puppet/property.rb index 282a52cf4..84e1a0360 100644 --- a/lib/puppet/property.rb +++ b/lib/puppet/property.rb @@ -55,10 +55,10 @@ class Puppet::Property < Puppet::Parameter # * <tt>:required_features</tt>: A list of features this value requires. # * <tt>:event</tt>: The event that should be returned when this value is set. # * <tt>:call</tt>: When to call any associated block. The default value - # is ``instead``, which means to call the value instead of calling the - # provider. You can also specify ``before`` or ``after``, which will + # is `instead`, which means to call the value instead of calling the + # provider. You can also specify `before` or `after`, which will # call both the block and the provider, according to the order you specify - # (the ``first`` refers to when the block is called, not the provider). + # (the `first` refers to when the block is called, not the provider). def self.newvalue(name, options = {}, &block) value = value_collection.newvalue(name, options, &block) @@ -181,10 +181,10 @@ class Puppet::Property < Puppet::Parameter def log(msg) Puppet::Util::Log.create( - + :level => resource[:loglevel], :message => msg, - + :source => self ) end diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb index 8f993dbc1..4456feb4e 100644 --- a/lib/puppet/provider.rb +++ b/lib/puppet/provider.rb @@ -12,7 +12,7 @@ class Puppet::Provider Puppet::Util.logmethods(self, true) class << self - # Include the util module so we have access to things like 'binary' + # Include the util module so we have access to things like 'which' include Puppet::Util, Puppet::Util::Docs include Puppet::Util::Logging attr_accessor :name @@ -43,7 +43,7 @@ class Puppet::Provider raise Puppet::DevError, "No command #{name} defined for provider #{self.name}" end - binary(command) + which(command) end # Define commands that are not optional. @@ -205,7 +205,7 @@ class Puppet::Provider dochook(:defaults) do if @defaults.length > 0 return " Default for " + @defaults.collect do |f, v| - "``#{f}`` == ``#{v}``" + "`#{f}` == `#{v}`" end.join(" and ") + "." end end @@ -213,7 +213,7 @@ class Puppet::Provider dochook(:commands) do if @commands.length > 0 return " Required binaries: " + @commands.collect do |n, c| - "``#{c}``" + "`#{c}`" end.join(", ") + "." end end @@ -221,7 +221,7 @@ class Puppet::Provider dochook(:features) do if features.length > 0 return " Supported features: " + features.collect do |f| - "``#{f}``" + "`#{f}`" end.join(", ") + "." end end diff --git a/lib/puppet/provider/confine/exists.rb b/lib/puppet/provider/confine/exists.rb index 085118b2a..09f94dfd9 100644 --- a/lib/puppet/provider/confine/exists.rb +++ b/lib/puppet/provider/confine/exists.rb @@ -6,10 +6,7 @@ class Puppet::Provider::Confine::Exists < Puppet::Provider::Confine end def pass?(value) - if for_binary? - return false unless value = binary(value) - end - value and FileTest.exist?(value) + value && (for_binary? ? which(value) : FileTest.exist?(value)) end def message(value) diff --git a/lib/puppet/provider/group/groupadd.rb b/lib/puppet/provider/group/groupadd.rb index e661ddd7f..82ed4c0c7 100644 --- a/lib/puppet/provider/group/groupadd.rb +++ b/lib/puppet/provider/group/groupadd.rb @@ -1,7 +1,7 @@ require 'puppet/provider/nameservice/objectadd' Puppet::Type.type(:group).provide :groupadd, :parent => Puppet::Provider::NameService::ObjectAdd do - desc "Group management via ``groupadd`` and its ilk. + desc "Group management via `groupadd` and its ilk. The default for most platforms diff --git a/lib/puppet/provider/group/ldap.rb b/lib/puppet/provider/group/ldap.rb index 2737feea6..86c72a5d3 100644 --- a/lib/puppet/provider/group/ldap.rb +++ b/lib/puppet/provider/group/ldap.rb @@ -1,11 +1,11 @@ require 'puppet/provider/ldap' Puppet::Type.type(:group).provide :ldap, :parent => Puppet::Provider::Ldap do - desc "Group management via ``ldap``. + desc "Group management via `ldap`. This provider requires that you have valid values for all of the - ldap-related settings, including ``ldapbase``. You will also almost - definitely need settings for ``ldapuser`` and ``ldappassword``, so that + ldap-related settings, including `ldapbase`. You will also almost + definitely need settings for `ldapuser` and `ldappassword`, so that your clients can write to ldap. Note that this provider will automatically generate a GID for you if you do diff --git a/lib/puppet/provider/group/pw.rb b/lib/puppet/provider/group/pw.rb index e3dd714ee..a054d1ff1 100644 --- a/lib/puppet/provider/group/pw.rb +++ b/lib/puppet/provider/group/pw.rb @@ -1,7 +1,7 @@ require 'puppet/provider/nameservice/pw' Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService::PW do - desc "Group management via ``pw``. + desc "Group management via `pw`. Only works on FreeBSD. diff --git a/lib/puppet/provider/host/parsed.rb b/lib/puppet/provider/host/parsed.rb index 4f15eff3f..a303c4bcf 100644 --- a/lib/puppet/provider/host/parsed.rb +++ b/lib/puppet/provider/host/parsed.rb @@ -8,66 +8,36 @@ else end - Puppet::Type.type(:host).provide( - :parsed, - :parent => Puppet::Provider::ParsedFile, - :default_target => hosts, - - :filetype => :flat -) do +Puppet::Type.type(:host).provide(:parsed,:parent => Puppet::Provider::ParsedFile, + :default_target => hosts,:filetype => :flat) do confine :exists => hosts text_line :comment, :match => /^#/ text_line :blank, :match => /^\s*$/ - record_line :parsed, :fields => %w{ip name host_aliases}, - :optional => %w{host_aliases}, - :rts => true do |line| - hash = {} - if line.sub!(/^(\S+)\s+(\S+)\s*/, '') - hash[:ip] = $1 - hash[:name] = $2 - - if line.empty? - hash[:host_aliases] = [] + record_line :parsed, :fields => %w{ip name host_aliases comment}, + :optional => %w{host_aliases comment}, + :match => /^(\S+)\s+(\S+)\s*(.*?)?(?:\s*#\s*(.*))?$/, + :post_parse => proc { |hash| + # An absent comment should match "comment => ''" + hash[:comment] = '' if hash[:comment].nil? or hash[:comment] == :absent + unless hash[:host_aliases].nil? or hash[:host_aliases] == :absent + hash[:host_aliases] = hash[:host_aliases].split(/\s+/) else - line.sub!(/\s*/, '') - line.sub!(/^([^#]+)\s*/) do |value| - aliases = $1 - unless aliases =~ /^\s*$/ - hash[:host_aliases] = aliases.split(/\s+/) - end - - "" - end + hash[:host_aliases] = [] end - else - raise Puppet::Error, "Could not match '#{line}'" - end - - hash[:host_aliases] = [] if hash[:host_aliases] == "" - - return hash - end - - # Convert the current object into a host-style string. - def self.to_line(hash) - return super unless hash[:record_type] == :parsed - [:ip, :name].each do |n| - raise ArgumentError, "#{n} is a required attribute for hosts" unless hash[n] and hash[n] != :absent - end - - str = "#{hash[:ip]}\t#{hash[:name]}" - - if hash.include? :host_aliases and !hash[:host_aliases].empty? - if hash[:host_aliases].is_a? Array + }, + :to_line => proc { |hash| + [:ip, :name].each do |n| + raise ArgumentError, "#{n} is a required attribute for hosts" unless hash[n] and hash[n] != :absent + end + str = "#{hash[:ip]}\t#{hash[:name]}" + if hash.include? :host_aliases and !hash[:host_aliases].empty? str += "\t#{hash[:host_aliases].join("\t")}" - else - raise ArgumentError, "Host aliases must be specified as an array" end - end - - str - end + if hash.include? :comment and !hash[:comment].empty? + str += "\t# #{hash[:comment]}" + end + str + } end - diff --git a/lib/puppet/provider/maillist/mailman.rb b/lib/puppet/provider/maillist/mailman.rb index 4fdc20a69..633642af7 100755 --- a/lib/puppet/provider/maillist/mailman.rb +++ b/lib/puppet/provider/maillist/mailman.rb @@ -2,11 +2,11 @@ require 'puppet/provider/parsedfile' Puppet::Type.type(:maillist).provide(:mailman) do if [ "CentOS", "RedHat", "Fedora" ].any? { |os| Facter.value(:operatingsystem) == os } - commands :list_lists => "/usr/lib/mailman/bin/list_lists", :rmlist => "/usr/lib/mailman/bin/rmlist", :newlist => "/usr/lib/mailman/bin/newlist" + commands :list_lists => "/usr/lib/mailman/bin/list_lists --bare", :rmlist => "/usr/lib/mailman/bin/rmlist", :newlist => "/usr/lib/mailman/bin/newlist" commands :mailman => "/usr/lib/mailman/mail/mailman" else # This probably won't work for non-Debian installs, but this path is sure not to be in the PATH. - commands :list_lists => "list_lists", :rmlist => "rmlist", :newlist => "newlist" + commands :list_lists => "list_lists --bare", :rmlist => "rmlist", :newlist => "newlist" commands :mailman => "/var/lib/mailman/mail/mailman" end @@ -14,10 +14,9 @@ Puppet::Type.type(:maillist).provide(:mailman) do # Return a list of existing mailman instances. def self.instances - list_lists.split("\n").reject { |line| line.include?("matching mailing lists") }.collect do |line| - name, description = line.sub(/^\s+/, '').sub(/\s+$/, '').split(/\s+-\s+/) - description = :absent if description.include?("no description available") - new(:ensure => :present, :name => name, :description => description) + list_lists.split("\n").collect do |line| + name = line.strip + new(:ensure => :present, :name => name) end end diff --git a/lib/puppet/provider/mcx/mcxcontent.rb b/lib/puppet/provider/mcx/mcxcontent.rb index cb5adc698..3ad437b53 100644 --- a/lib/puppet/provider/mcx/mcxcontent.rb +++ b/lib/puppet/provider/mcx/mcxcontent.rb @@ -53,39 +53,31 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do confine :operatingsystem => :darwin defaultfor :operatingsystem => :darwin - # self.instances is all important. - # This is the only class method, it returns - # an array of instances of this class. def self.instances mcx_list = [] - for ds_type in TypeMap.keys + TypeMap.keys.each do |ds_type| ds_path = "/Local/Default/#{TypeMap[ds_type]}" output = dscl 'localhost', '-list', ds_path member_list = output.split - for ds_name in member_list + member_list.each do |ds_name| content = mcxexport(ds_type, ds_name) if content.empty? Puppet.debug "/#{TypeMap[ds_type]}/#{ds_name} has no MCX data." else # This node has MCX data. - rsrc = self.new( - :name => "/#{TypeMap[ds_type]}/#{ds_name}", - :ds_type => ds_type, - :ds_name => ds_name, - - :content => content) - mcx_list << rsrc + mcx_list << self.new( + :name => "/#{TypeMap[ds_type]}/#{ds_name}", + :ds_type => ds_type, + :ds_name => ds_name, + :content => content + ) end end end mcx_list end - private - - # mcxexport is used by instances, and therefore - # a class method. def self.mcxexport(ds_type, ds_name) ds_t = TypeMap[ds_type] ds_n = ds_name.to_s @@ -93,9 +85,49 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do dscl 'localhost', '-mcxexport', ds_path end + + def create + self.content=(resource[:content]) + end + + def destroy + ds_parms = get_dsparams + ds_t = TypeMap[ds_parms[:ds_type]] + ds_n = ds_parms[:ds_name].to_s + ds_path = "/Local/Default/#{ds_t}/#{ds_n}" + + dscl 'localhost', '-mcxdelete', ds_path + end + + def exists? + begin + has_mcx? + rescue Puppet::ExecutionFailure => e + return false + end + end + + def content + ds_parms = get_dsparams + + self.class.mcxexport(ds_parms[:ds_type], ds_parms[:ds_name]) + end + + def content=(value) + # dscl localhost -mcximport + ds_parms = get_dsparams + + mcximport(ds_parms[:ds_type], ds_parms[:ds_name], resource[:content]) + end + + private + + def has_mcx? + !content.empty? + end + def mcximport(ds_type, ds_name, val) ds_t = TypeMap[ds_type] - ds_n = ds_name.to_s ds_path = "/Local/Default/#{ds_t}/#{ds_name}" tmp = Tempfile.new('puppet_mcx') @@ -111,33 +143,31 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do # Given the resource name string, parse ds_type out. def parse_type(name) - tmp = name.split('/')[1] - if ! tmp.is_a? String + ds_type = name.split('/')[1] + unless ds_type raise MCXContentProviderException, "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter." end # De-pluralize and downcase. - tmp = tmp.chop.downcase.to_sym - if not TypeMap.keys.member? tmp + ds_type = ds_type.chop.downcase.to_sym + unless TypeMap.key? ds_type raise MCXContentProviderException, "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter." end - tmp + ds_type end # Given the resource name string, parse ds_name out. def parse_name(name) ds_name = name.split('/')[2] - if ! ds_name.is_a? String + unless ds_name raise MCXContentProviderException, "Could not parse ds_name from resource name '#{name}'. Specify with ds_name parameter." end ds_name end - # Gather ds_type and ds_name from resource or - # parse it out of the name. - # This is a private instance method, not a class method. + # Gather ds_type and ds_name from resource or parse it out of the name. def get_dsparams ds_type = resource[:ds_type] ds_type ||= parse_type(resource[:name]) @@ -146,60 +176,10 @@ Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do ds_name = resource[:ds_name] ds_name ||= parse_name(resource[:name]) - rval = { + { :ds_type => ds_type.to_sym, :ds_name => ds_name, } - - return rval - - end - - public - - def create - self.content=(resource[:content]) - end - - def destroy - ds_parms = get_dsparams - ds_t = TypeMap[ds_parms[:ds_type]] - ds_n = ds_parms[:ds_name].to_s - ds_path = "/Local/Default/#{ds_t}/#{ds_n}" - - dscl 'localhost', '-mcxdelete', ds_path - end - - def exists? - # JJM Just re-use the content method and see if it's empty. - begin - mcx = content - rescue Puppet::ExecutionFailure => e - return false - end - has_mcx = ! mcx.empty? - end - - def content - ds_parms = get_dsparams - - mcx = self.class.mcxexport( - ds_parms[:ds_type], - - ds_parms[:ds_name]) - mcx - end - - def content=(value) - # dscl localhost -mcximport - ds_parms = get_dsparams - - mcx = mcximport( - ds_parms[:ds_type], - ds_parms[:ds_name], - - resource[:content]) - mcx end end diff --git a/lib/puppet/provider/mount.rb b/lib/puppet/provider/mount.rb index 393ae56c9..8c7b24bd4 100644 --- a/lib/puppet/provider/mount.rb +++ b/lib/puppet/provider/mount.rb @@ -41,7 +41,7 @@ module Puppet::Provider::Mount case platform when "Darwin" line =~ / on #{name} / or line =~ %r{ on /private/var/automount#{name}} - when "Solaris" + when "Solaris", "HP-UX" line =~ /^#{name} on / else line =~ / on #{name} / diff --git a/lib/puppet/provider/nameservice.rb b/lib/puppet/provider/nameservice.rb index 7339b646e..d57052bd9 100644 --- a/lib/puppet/provider/nameservice.rb +++ b/lib/puppet/provider/nameservice.rb @@ -165,6 +165,9 @@ class Puppet::Provider::NameService < Puppet::Provider begin execute(self.addcmd) + if feature?(:manages_password_age) && (cmd = passcmd) + execute(cmd) + end rescue Puppet::ExecutionFailure => detail raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}" end diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb index 965a2aa60..106d99eb3 100644 --- a/lib/puppet/provider/nameservice/directoryservice.rb +++ b/lib/puppet/provider/nameservice/directoryservice.rb @@ -321,6 +321,31 @@ class DirectoryService < Puppet::Provider::NameService password_hash end + # Unlike most other *nixes, OS X doesn't provide built in functionality + # for automatically assigning uids and gids to accounts, so we set up these + # methods for consumption by functionality like --mkusers + # By default we restrict to a reasonably sane range for system accounts + def self.next_system_id(id_type, min_id=20) + dscl_args = ['.', '-list'] + if id_type == 'uid' + dscl_args << '/Users' << 'uid' + elsif id_type == 'gid' + dscl_args << '/Groups' << 'gid' + else + fail("Invalid id_type #{id_type}. Only 'uid' and 'gid' supported") + end + dscl_out = dscl(dscl_args) + # We're ok with throwing away negative uids here. + ids = dscl_out.split.compact.collect { |l| l.to_i if l.match(/^\d+$/) } + ids.compact!.sort! { |a,b| a.to_f <=> b.to_f } + # We're just looking for an unused id in our sorted array. + ids.each_index do |i| + next_id = ids[i] + 1 + return next_id if ids[i+1] != next_id and next_id >= min_id + end + end + + def ensure=(ensure_value) super # We need to loop over all valid properties for the type we're @@ -422,7 +447,14 @@ class DirectoryService < Puppet::Provider::NameService # Now we create all the standard properties Puppet::Type.type(@resource.class.name).validproperties.each do |property| next if property == :ensure - if value = @resource.should(property) and value != "" + value = @resource.should(property) + if property == :gid and value.nil? + value = self.class.next_system_id(id_type='gid') + end + if property == :uid and value.nil? + value = self.class.next_system_id(id_type='uid') + end + if value != "" and not value.nil? if property == :members add_members(nil, value) else diff --git a/lib/puppet/provider/nameservice/objectadd.rb b/lib/puppet/provider/nameservice/objectadd.rb index 80c142982..dbb9f306f 100644 --- a/lib/puppet/provider/nameservice/objectadd.rb +++ b/lib/puppet/provider/nameservice/objectadd.rb @@ -13,7 +13,8 @@ class ObjectAdd < Puppet::Provider::NameService end def modifycmd(param, value) - cmd = [command(:modify), flag(param), value] + cmd = [command(param.to_s =~ /password_.+_age/ ? :password : :modify)] + cmd << flag(param) << value if @resource.allowdupe? && ((param == :uid) || (param == :gid and self.class.name == :groupadd)) cmd << "-o" end diff --git a/lib/puppet/provider/package/apple.rb b/lib/puppet/provider/package/apple.rb index 0946de47f..b5bb9102f 100755 --- a/lib/puppet/provider/package/apple.rb +++ b/lib/puppet/provider/package/apple.rb @@ -5,7 +5,7 @@ Puppet::Type.type(:package).provide :apple, :parent => Puppet::Provider::Package desc "Package management based on OS X's builtin packaging system. This is essentially the simplest and least functional package system in existence -- it only supports installation; no deletion or upgrades. The provider will - automatically add the ``.pkg`` extension, so leave that off when specifying + automatically add the `.pkg` extension, so leave that off when specifying the package name." confine :operatingsystem => :darwin diff --git a/lib/puppet/provider/package/apt.rb b/lib/puppet/provider/package/apt.rb index d055e7552..2fc787419 100755 --- a/lib/puppet/provider/package/apt.rb +++ b/lib/puppet/provider/package/apt.rb @@ -2,7 +2,7 @@ Puppet::Type.type(:package).provide :apt, :parent => :dpkg, :source => :dpkg do # Provide sorting functionality include Puppet::Util::Package - desc "Package management via ``apt-get``." + desc "Package management via `apt-get`." has_feature :versionable @@ -14,6 +14,10 @@ Puppet::Type.type(:package).provide :apt, :parent => :dpkg, :source => :dpkg do ENV['DEBIAN_FRONTEND'] = "noninteractive" + # disable common apt helpers to allow non-interactive package installs + ENV['APT_LISTBUGS_FRONTEND'] = "none" + ENV['APT_LISTCHANGES_FRONTEND'] = "none" + # A derivative of DPKG; this is how most people actually manage # Debian boxes, and the only thing that differs is that it can # install packages from remote sites. diff --git a/lib/puppet/provider/package/aptitude.rb b/lib/puppet/provider/package/aptitude.rb index 557e657a4..8bdf984e6 100755 --- a/lib/puppet/provider/package/aptitude.rb +++ b/lib/puppet/provider/package/aptitude.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :aptitude, :parent => :apt, :source => :dpkg do - desc "Package management via ``aptitude``." + desc "Package management via `aptitude`." has_feature :versionable diff --git a/lib/puppet/provider/package/aptrpm.rb b/lib/puppet/provider/package/aptrpm.rb index d7842089f..2eb33c72b 100644 --- a/lib/puppet/provider/package/aptrpm.rb +++ b/lib/puppet/provider/package/aptrpm.rb @@ -2,7 +2,7 @@ Puppet::Type.type(:package).provide :aptrpm, :parent => :rpm, :source => :rpm do # Provide sorting functionality include Puppet::Util::Package - desc "Package management via ``apt-get`` ported to ``rpm``." + desc "Package management via `apt-get` ported to `rpm`." has_feature :versionable diff --git a/lib/puppet/provider/package/blastwave.rb b/lib/puppet/provider/package/blastwave.rb index 9f1f1ec19..e9c84845f 100755 --- a/lib/puppet/provider/package/blastwave.rb +++ b/lib/puppet/provider/package/blastwave.rb @@ -1,6 +1,6 @@ # Packaging using Blastwave's pkg-get program. Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun do - desc "Package management using Blastwave.org's ``pkg-get`` command on Solaris." + desc "Package management using Blastwave.org's `pkg-get` command on Solaris." pkgget = "pkg-get" pkgget = "/opt/csw/bin/pkg-get" if FileTest.executable?("/opt/csw/bin/pkg-get") diff --git a/lib/puppet/provider/package/dpkg.rb b/lib/puppet/provider/package/dpkg.rb index bee63bfba..7b34b09af 100755 --- a/lib/puppet/provider/package/dpkg.rb +++ b/lib/puppet/provider/package/dpkg.rb @@ -1,8 +1,8 @@ require 'puppet/provider/package' Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package do - desc "Package management via ``dpkg``. Because this only uses ``dpkg`` - and not ``apt``, you must specify the source of any packages you want + desc "Package management via `dpkg`. Because this only uses `dpkg` + and not `apt`, you must specify the source of any packages you want to manage." has_feature :holdable diff --git a/lib/puppet/provider/package/fink.rb b/lib/puppet/provider/package/fink.rb index 5cf47860e..db991397a 100755 --- a/lib/puppet/provider/package/fink.rb +++ b/lib/puppet/provider/package/fink.rb @@ -2,7 +2,7 @@ Puppet::Type.type(:package).provide :fink, :parent => :dpkg, :source => :dpkg do # Provide sorting functionality include Puppet::Util::Package - desc "Package management via ``fink``." + desc "Package management via `fink`." commands :fink => "/sw/bin/fink" commands :aptget => "/sw/bin/apt-get" diff --git a/lib/puppet/provider/package/gem.rb b/lib/puppet/provider/package/gem.rb index 8d70b756f..19414cec4 100755 --- a/lib/puppet/provider/package/gem.rb +++ b/lib/puppet/provider/package/gem.rb @@ -3,7 +3,7 @@ require 'uri' # Ruby gems support. Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package do - desc "Ruby Gem support. If a URL is passed via ``source``, then that URL is used as the + desc "Ruby Gem support. If a URL is passed via `source`, then that URL is used as the remote gem repository; if a source is present but is not a valid URL, it will be interpreted as the path to a local gem file. If source is not present at all, the gem will be installed from the default gem repositories." diff --git a/lib/puppet/provider/package/openbsd.rb b/lib/puppet/provider/package/openbsd.rb index ca477e56a..bb07d894a 100755 --- a/lib/puppet/provider/package/openbsd.rb +++ b/lib/puppet/provider/package/openbsd.rb @@ -2,8 +2,7 @@ require 'puppet/provider/package' # Packaging on OpenBSD. Doesn't work anywhere else that I know of. Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Package do - include Puppet::Util::Execution - desc "OpenBSD's form of ``pkg_add`` support." + desc "OpenBSD's form of `pkg_add` support." commands :pkginfo => "pkg_info", :pkgadd => "pkg_add", :pkgdelete => "pkg_delete" @@ -61,18 +60,15 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa "You must specify a package source for BSD packages" end - old_ensure = @resource[:ensure] - - if @resource[:source] =~ /\/$/ - withenv :PKG_PATH => @resource[:source] do - @resource[:ensure] = old_ensure if (@resource[:ensure] = get_version) == nil - full_name = [ @resource[:name], @resource[:ensure], @resource[:flavor] ] - pkgadd full_name.join('-').chomp('-') - end + if @resource[:source][-1,1] == ::File::PATH_SEPARATOR + e_vars = { :PKG_PATH => @resource[:source] } + full_name = [ @resource[:name], get_version || @resource[:ensure], @resource[:flavor] ].join('-').chomp('-') else - pkgadd @resource[:source] + e_vars = {} + full_name = @resource[:source] end + Puppet::Util::Execution::withenv(e_vars) { pkgadd full_name } end def get_version diff --git a/lib/puppet/provider/package/rpm.rb b/lib/puppet/provider/package/rpm.rb index d33a4f2f3..72dc260a4 100755 --- a/lib/puppet/provider/package/rpm.rb +++ b/lib/puppet/provider/package/rpm.rb @@ -1,7 +1,7 @@ require 'puppet/provider/package' # RPM packaging. Should work anywhere that has rpm installed. Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Provider::Package do - desc "RPM packaging support; should work anywhere with a working ``rpm`` + desc "RPM packaging support; should work anywhere with a working `rpm` binary." has_feature :versionable diff --git a/lib/puppet/provider/package/rug.rb b/lib/puppet/provider/package/rug.rb index 7028cc9e5..28729952d 100644 --- a/lib/puppet/provider/package/rug.rb +++ b/lib/puppet/provider/package/rug.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :rug, :parent => :rpm do - desc "Support for suse ``rug`` package manager." + desc "Support for suse `rug` package manager." has_feature :versionable diff --git a/lib/puppet/provider/package/sunfreeware.rb b/lib/puppet/provider/package/sunfreeware.rb index 53f03ed6e..4745ea1eb 100755 --- a/lib/puppet/provider/package/sunfreeware.rb +++ b/lib/puppet/provider/package/sunfreeware.rb @@ -1,7 +1,7 @@ # At this point, it's an exact copy of the Blastwave stuff. Puppet::Type.type(:package).provide :sunfreeware, :parent => :blastwave, :source => :sun do - desc "Package management using sunfreeware.com's ``pkg-get`` command on Solaris. - At this point, support is exactly the same as ``blastwave`` support and + desc "Package management using sunfreeware.com's `pkg-get` command on Solaris. + At this point, support is exactly the same as `blastwave` support and has not actually been tested." commands :pkgget => "pkg-get" diff --git a/lib/puppet/provider/package/up2date.rb b/lib/puppet/provider/package/up2date.rb index 5ff32bedc..243bc6c6b 100644 --- a/lib/puppet/provider/package/up2date.rb +++ b/lib/puppet/provider/package/up2date.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :up2date, :parent => :rpm, :source => :rpm do - desc "Support for Red Hat's proprietary ``up2date`` package update + desc "Support for Red Hat's proprietary `up2date` package update mechanism." commands :up2date => "/usr/sbin/up2date-nox" diff --git a/lib/puppet/provider/package/urpmi.rb b/lib/puppet/provider/package/urpmi.rb index 88a17ccb4..425d77849 100644 --- a/lib/puppet/provider/package/urpmi.rb +++ b/lib/puppet/provider/package/urpmi.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :urpmi, :parent => :rpm, :source => :rpm do - desc "Support via ``urpmi``." + desc "Support via `urpmi`." commands :urpmi => "urpmi", :urpmq => "urpmq", :rpm => "rpm" if command('rpm') diff --git a/lib/puppet/provider/package/yum.rb b/lib/puppet/provider/package/yum.rb index 07f68ddb1..6ed966fbd 100755 --- a/lib/puppet/provider/package/yum.rb +++ b/lib/puppet/provider/package/yum.rb @@ -1,5 +1,6 @@ +require 'puppet/util/package' Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do - desc "Support via ``yum``." + desc "Support via `yum`." has_feature :versionable @@ -52,6 +53,7 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do should = @resource.should(:ensure) self.debug "Ensuring => #{should}" wanted = @resource[:name] + operation = :install # XXX: We don't actually deal with epochs here. case should @@ -61,9 +63,14 @@ Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do else # Add the package version wanted += "-#{should}" + is = self.query + if is && Puppet::Util::Package.versioncmp(should, is[:ensure]) < 0 + self.debug "Downgrading package #{@resource[:name]} from version #{is[:ensure]} to #{should}" + operation = :downgrade + end end - output = yum "-d", "0", "-e", "0", "-y", :install, wanted + output = yum "-d", "0", "-e", "0", "-y", operation, wanted is = self.query raise Puppet::Error, "Could not find package #{self.name}" unless is diff --git a/lib/puppet/provider/package/zypper.rb b/lib/puppet/provider/package/zypper.rb index d56c72549..f129ef6e6 100644 --- a/lib/puppet/provider/package/zypper.rb +++ b/lib/puppet/provider/package/zypper.rb @@ -1,5 +1,5 @@ Puppet::Type.type(:package).provide :zypper, :parent => :rpm do - desc "Support for SuSE ``zypper`` package manager. Found in SLES10sp2+ and SLES11" + desc "Support for SuSE `zypper` package manager. Found in SLES10sp2+ and SLES11" has_feature :versionable diff --git a/lib/puppet/provider/service/base.rb b/lib/puppet/provider/service/base.rb index 70d764187..211e7f964 100755 --- a/lib/puppet/provider/service/base.rb +++ b/lib/puppet/provider/service/base.rb @@ -5,7 +5,7 @@ Puppet::Type.type(:service).provide :base do minimum you can specify is a binary for starting the process, and this same binary will be searched for in the process table to stop the service. It is preferable to specify start, stop, and status commands, - akin to how you would do so using ``init``. + akin to how you would do so using `init`. " diff --git a/lib/puppet/provider/service/bsd.rb b/lib/puppet/provider/service/bsd.rb index 2e00c33f1..e2a0e35f7 100644 --- a/lib/puppet/provider/service/bsd.rb +++ b/lib/puppet/provider/service/bsd.rb @@ -1,8 +1,8 @@ # Manage FreeBSD services. Puppet::Type.type(:service).provide :bsd, :parent => :init do - desc "FreeBSD's (and probably NetBSD?) form of ``init``-style service management. + desc "FreeBSD's (and probably NetBSD?) form of `init`-style service management. - Uses ``rc.conf.d`` for service enabling and disabling. + Uses `rc.conf.d` for service enabling and disabling. " diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb index 4379f1b59..3d09e2849 100755 --- a/lib/puppet/provider/service/debian.rb +++ b/lib/puppet/provider/service/debian.rb @@ -1,10 +1,10 @@ # Manage debian services. Start/stop is the same as InitSvc, but enable/disable # is special. Puppet::Type.type(:service).provide :debian, :parent => :init do - desc "Debian's form of ``init``-style management. + desc "Debian's form of `init`-style management. The only difference is that this supports service enabling and disabling - via ``update-rc.d`` and determines enabled status via ``invoke-rc.d``. + via `update-rc.d` and determines enabled status via `invoke-rc.d`. " diff --git a/lib/puppet/provider/service/freebsd.rb b/lib/puppet/provider/service/freebsd.rb index 10970e4da..f8c7134f0 100644 --- a/lib/puppet/provider/service/freebsd.rb +++ b/lib/puppet/provider/service/freebsd.rb @@ -18,6 +18,9 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do def rcvar rcvar = execute([self.initscript, :rcvar], :failonfail => true, :squelch => false) rcvar = rcvar.split("\n") + rcvar.delete_if {|str| str =~ /^#\s*$/} + rcvar[1] = rcvar[1].gsub(/^\$/, '') + rcvar end # Extract service name @@ -44,7 +47,7 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do def rcvar_value value = self.rcvar[1] self.error("No rcvar value found in rcvar") if value.nil? - value = value.gsub!(/(.*)_enable=\"?(.*)\"?/, '\2') + value = value.gsub!(/(.*)_enable="?(\w+)"?/, '\2') self.error("rcvar value is empty") if value.nil? self.debug("rcvar value is #{value}") value @@ -78,7 +81,7 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do # Add a new setting to the rc files def rc_add(service, rcvar, yesno) - append = "\n\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\"" + append = "\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\"\n" # First, try the one-file-per-service style if File.exists?(@@rcconf_dir) File.open(@@rcconf_dir + "/#{service}", File::WRONLY | File::APPEND | File::CREAT, 0644) { diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb index 08250a06a..382c74267 100644 --- a/lib/puppet/provider/service/gentoo.rb +++ b/lib/puppet/provider/service/gentoo.rb @@ -1,9 +1,9 @@ # Manage gentoo services. Start/stop is the same as InitSvc, but enable/disable # is special. Puppet::Type.type(:service).provide :gentoo, :parent => :init do - desc "Gentoo's form of ``init``-style service management. + desc "Gentoo's form of `init`-style service management. - Uses ``rc-update`` for service enabling and disabling. + Uses `rc-update` for service enabling and disabling. " diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb index 6abff12db..447c01aa5 100755 --- a/lib/puppet/provider/service/init.rb +++ b/lib/puppet/provider/service/init.rb @@ -3,9 +3,9 @@ Puppet::Type.type(:service).provide :init, :parent => :base do desc "Standard init service management. - This provider assumes that the init script has no ``status`` command, + This provider assumes that the init script has no `status` command, because so few scripts do, so you need to either provide a status - command or specify via ``hasstatus`` that one already exists in the + command or specify via `hasstatus` that one already exists in the init script. " diff --git a/lib/puppet/provider/service/launchd.rb b/lib/puppet/provider/service/launchd.rb index 970359539..1632edabf 100644 --- a/lib/puppet/provider/service/launchd.rb +++ b/lib/puppet/provider/service/launchd.rb @@ -38,6 +38,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do commands :launchctl => "/bin/launchctl" commands :sw_vers => "/usr/bin/sw_vers" + commands :plutil => "/usr/bin/plutil" defaultfor :operatingsystem => :darwin confine :operatingsystem => :darwin @@ -52,6 +53,12 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do Launchd_Overrides = "/var/db/launchd.db/com.apple.launchd/overrides.plist" + # Read a plist, whether its format is XML or in Apple's "binary1" + # format. + def self.read_plist(path) + Plist::parse_xml(plutil('-convert', 'xml1', '-o', '/dev/stdout', path)) + end + # returns a label => path map for either all jobs, or just a single # job if the label is specified def self.jobsearch(label=nil) @@ -62,8 +69,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do next if f =~ /^\..*$/ next if FileTest.directory?(f) fullpath = File.join(path, f) - job = Plist::parse_xml(fullpath) - if job and job.has_key?("Label") + if FileTest.file?(fullpath) and job = read_plist(fullpath) and job.has_key?("Label") if job["Label"] == label return { label => fullpath } else @@ -118,8 +124,11 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do def plist_from_label(label) job = self.class.jobsearch(label) job_path = job[label] - job_plist = Plist::parse_xml(job_path) - raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}") if not job_plist + if FileTest.file?(job_path) + job_plist = self.class.read_plist(job_path) + else + raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}") + end [job_path, job_plist] end @@ -200,9 +209,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled") if self.class.get_macosx_version_major == "10.6": - overrides = Plist::parse_xml(Launchd_Overrides) - - unless overrides.nil? + if FileTest.file?(Launchd_Overrides) and overrides = self.class.read_plist(Launchd_Overrides) if overrides.has_key?(resource[:name]) overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled") end @@ -227,7 +234,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do # versions this is stored in the job plist itself. def enable if self.class.get_macosx_version_major == "10.6" - overrides = Plist::parse_xml(Launchd_Overrides) + overrides = self.class.read_plist(Launchd_Overrides) overrides[resource[:name]] = { "Disabled" => false } Plist::Emit.save_plist(overrides, Launchd_Overrides) else @@ -242,7 +249,7 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do def disable if self.class.get_macosx_version_major == "10.6" - overrides = Plist::parse_xml(Launchd_Overrides) + overrides = self.class.read_plist(Launchd_Overrides) overrides[resource[:name]] = { "Disabled" => true } Plist::Emit.save_plist(overrides, Launchd_Overrides) else diff --git a/lib/puppet/provider/service/redhat.rb b/lib/puppet/provider/service/redhat.rb index 3ca67d66f..e851a488d 100755 --- a/lib/puppet/provider/service/redhat.rb +++ b/lib/puppet/provider/service/redhat.rb @@ -1,9 +1,9 @@ # Manage Red Hat services. Start/stop uses /sbin/service and enable/disable uses chkconfig Puppet::Type.type(:service).provide :redhat, :parent => :init, :source => :init do - desc "Red Hat's (and probably many others) form of ``init``-style service management: + desc "Red Hat's (and probably many others) form of `init`-style service management: - Uses ``chkconfig`` for service enabling and disabling. + Uses `chkconfig` for service enabling and disabling. " diff --git a/lib/puppet/provider/service/upstart.rb b/lib/puppet/provider/service/upstart.rb new file mode 100755 index 000000000..54971eeac --- /dev/null +++ b/lib/puppet/provider/service/upstart.rb @@ -0,0 +1,73 @@ +Puppet::Type.type(:service).provide :upstart, :parent => :init do + desc "Ubuntu service manager upstart. + + This provider manages upstart jobs which have replaced initd. + + See: + * http://upstart.ubuntu.com/ + " + # confine to :ubuntu for now because I haven't tested on other platforms + confine :operatingsystem => :ubuntu #[:ubuntu, :fedora, :debian] + + commands :start => "/sbin/start", + :stop => "/sbin/stop", + :restart => "/sbin/restart", + :status_exec => "/sbin/status", + :initctl => "/sbin/initctl" + + # upstart developer haven't implemented initctl enable/disable yet: + # http://www.linuxplanet.com/linuxplanet/tutorials/7033/2/ + # has_feature :enableable + + def self.instances + instances = [] + execpipe("#{command(:initctl)} list") { |process| + process.each { |line| + # needs special handling of services such as network-interface: + # initctl list: + # network-interface (lo) start/running + # network-interface (eth0) start/running + # network-interface-security start/running + name = \ + if matcher = line.match(/^(network-interface)\s\(([^\)]+)\)/) + "#{matcher[1]} INTERFACE=#{matcher[2]}" + else + line.split.first + end + instances << new(:name => name) + } + } + instances + end + + def startcmd + [command(:start), @resource[:name]] + end + + def stopcmd + [command(:stop), @resource[:name]] + end + + def restartcmd + (@resource[:hasrestart] == :true) && [command(:restart), @resource[:name]] + end + + def status + # allows user override of status command + if @resource[:status] + ucommand(:status, false) + if $?.exitstatus == 0 + return :running + else + return :stopped + end + else + output = status_exec(@resource[:name].split) + if (! $?.nil?) && (output =~ /start\//) + return :running + else + return :stopped + end + end + end +end diff --git a/lib/puppet/provider/ssh_authorized_key/parsed.rb b/lib/puppet/provider/ssh_authorized_key/parsed.rb index 82f6b8881..6a3855c0e 100644 --- a/lib/puppet/provider/ssh_authorized_key/parsed.rb +++ b/lib/puppet/provider/ssh_authorized_key/parsed.rb @@ -61,6 +61,13 @@ require 'puppet/provider/parsedfile' Dir.mkdir(dir, dir_perm) File.chown(uid, nil, dir) end + + # ParsedFile usually calls backup_target much later in the flush process, + # but our SUID makes that fail to open filebucket files for writing. + # Fortunately, there's already logic to make sure it only ever happens once, + # so calling it here supresses the later attempt by our superclass's flush method. + self.class.backup_target(target) + Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super } File.chown(uid, nil, target) File.chmod(file_perm, target) diff --git a/lib/puppet/provider/user/hpux.rb b/lib/puppet/provider/user/hpux.rb index 50506c4cd..983970935 100644 --- a/lib/puppet/provider/user/hpux.rb +++ b/lib/puppet/provider/user/hpux.rb @@ -26,5 +26,4 @@ Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do def modifycmd(param,value) super.insert(1,"-F") end - end diff --git a/lib/puppet/provider/user/ldap.rb b/lib/puppet/provider/user/ldap.rb index df082c569..75a9667b3 100644 --- a/lib/puppet/provider/user/ldap.rb +++ b/lib/puppet/provider/user/ldap.rb @@ -1,10 +1,10 @@ require 'puppet/provider/ldap' Puppet::Type.type(:user).provide :ldap, :parent => Puppet::Provider::Ldap do - desc "User management via ``ldap``. This provider requires that you + desc "User management via `ldap`. This provider requires that you have valid values for all of the ldap-related settings, - including ``ldapbase``. You will also almost definitely need settings - for ``ldapuser`` and ``ldappassword``, so that your clients can write + including `ldapbase`. You will also almost definitely need settings + for `ldapuser` and `ldappassword`, so that your clients can write to ldap. Note that this provider will automatically generate a UID for you if diff --git a/lib/puppet/provider/user/pw.rb b/lib/puppet/provider/user/pw.rb index 345d924bf..a5988cad1 100644 --- a/lib/puppet/provider/user/pw.rb +++ b/lib/puppet/provider/user/pw.rb @@ -1,7 +1,7 @@ require 'puppet/provider/nameservice/pw' Puppet::Type.type(:user).provide :pw, :parent => Puppet::Provider::NameService::PW do - desc "User management via ``pw`` on FreeBSD." + desc "User management via `pw` on FreeBSD." commands :pw => "pw" has_features :manages_homedir, :allows_duplicates diff --git a/lib/puppet/provider/user/user_role_add.rb b/lib/puppet/provider/user/user_role_add.rb index ea1b01b3b..2377f9e65 100644 --- a/lib/puppet/provider/user/user_role_add.rb +++ b/lib/puppet/provider/user/user_role_add.rb @@ -2,17 +2,19 @@ require 'puppet/util/user_attr' Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => :useradd do - desc "User management inherits ``useradd`` and adds logic to manage roles on Solaris using roleadd." + desc "User management inherits `useradd` and adds logic to manage roles on Solaris using roleadd." defaultfor :operatingsystem => :solaris - commands :add => "useradd", :delete => "userdel", :modify => "usermod", :role_add => "roleadd", :role_delete => "roledel", :role_modify => "rolemod" + commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "passwd", :role_add => "roleadd", :role_delete => "roledel", :role_modify => "rolemod" options :home, :flag => "-d", :method => :dir options :comment, :method => :gecos options :groups, :flag => "-G" options :roles, :flag => "-R" options :auths, :flag => "-A" options :profiles, :flag => "-P" + options :password_min_age, :flag => "-n" + options :password_max_age, :flag => "-x" verify :gid, "GID must be an integer" do |value| value.is_a? Integer @@ -22,14 +24,14 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => value !~ /\s/ end - has_features :manages_homedir, :allows_duplicates, :manages_solaris_rbac, :manages_passwords + has_features :manages_homedir, :allows_duplicates, :manages_solaris_rbac, :manages_passwords, :manages_password_age #must override this to hand the keyvalue pairs def add_properties cmd = [] Puppet::Type.type(:user).validproperties.each do |property| #skip the password because we can't create it with the solaris useradd - next if [:ensure, :password].include?(property) + next if [:ensure, :password, :password_min_age, :password_max_age].include?(property) # 1680 Now you can set the hashed passwords on solaris:lib/puppet/provider/user/user_role_add.rb # the value needs to be quoted, mostly because -c might # have spaces in it @@ -79,6 +81,9 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => run(transition("normal"), "transition role to") else run(addcmd, "create") + if cmd = passcmd + run(cmd, "change password policy for") + end end # added to handle case when password is specified self.password = @resource[:password] if @resource[:password] @@ -140,14 +145,23 @@ Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs") end - #Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return the hashed pw (the second entry) + #Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return it #No abstraction, all esoteric knowledge of file formats, yay + def shadow_entry + return @shadow_entry if defined? @shadow_entry + @shadow_entry = File.readlines("/etc/shadow").reject { |r| r =~ /^[^\w]/ }.collect { |l| l.chomp.split(':') }.find { |user, _| user == @resource[:name] } + end + def password - #got perl? - if ary = File.readlines("/etc/shadow").reject { |r| r =~ /^[^\w]/}.collect { |l| l.split(':')[0..1] }.find { |user, passwd| user == @resource[:name] } - pass = ary[1] - end - pass + shadow_entry[1] if shadow_entry + end + + def password_min_age + shadow_entry ? shadow_entry[3] : :absent + end + + def password_max_age + shadow_entry ? shadow_entry[4] : :absent end #Read in /etc/shadow, find the line for our used and rewrite it with the new pw diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb index ec87694d7..ba406cc63 100644 --- a/lib/puppet/provider/user/useradd.rb +++ b/lib/puppet/provider/user/useradd.rb @@ -1,13 +1,15 @@ require 'puppet/provider/nameservice/objectadd' Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameService::ObjectAdd do - desc "User management via ``useradd`` and its ilk. Note that you will need to install the ``Shadow Password`` Ruby library often known as ruby-libshadow to manage user passwords." + desc "User management via `useradd` and its ilk. Note that you will need to install the `Shadow Password` Ruby library often known as ruby-libshadow to manage user passwords." - commands :add => "useradd", :delete => "userdel", :modify => "usermod" + commands :add => "useradd", :delete => "userdel", :modify => "usermod", :password => "chage" options :home, :flag => "-d", :method => :dir options :comment, :method => :gecos options :groups, :flag => "-G" + options :password_min_age, :flag => "-m" + options :password_max_age, :flag => "-M" verify :gid, "GID must be an integer" do |value| value.is_a? Integer @@ -17,9 +19,9 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ value !~ /\s/ end - has_features :manages_homedir, :allows_duplicates + has_features :manages_homedir, :allows_duplicates, :manages_expiry - has_feature :manages_passwords if Puppet.features.libshadow? + has_features :manages_passwords, :manages_password_age if Puppet.features.libshadow? def check_allow_dup @resource.allowdupe? ? ["-o"] : [] @@ -35,10 +37,20 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ cmd end + def check_manage_expiry + cmd = [] + if @resource[:expiry] + cmd << "-e #{@resource[:expiry]}" + end + + cmd + end + def add_properties cmd = [] Puppet::Type.type(:user).validproperties.each do |property| next if property == :ensure + next if property.to_s =~ /password_.+_age/ # the value needs to be quoted, mostly because -c might # have spaces in it if value = @resource.should(property) and value != "" @@ -53,9 +65,37 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ cmd += add_properties cmd += check_allow_dup cmd += check_manage_home + cmd += check_manage_expiry cmd << @resource[:name] end + def passcmd + age_limits = [:password_min_age, :password_max_age].select { |property| @resource.should(property) } + if age_limits.empty? + nil + else + [command(:password),age_limits.collect { |property| [flag(property), @resource.should(property)]}, @resource[:name]].flatten + end + end + + def password_min_age + if Puppet.features.libshadow? + if ent = Shadow::Passwd.getspnam(@resource.name) + return ent.sp_min + end + end + :absent + end + + def password_max_age + if Puppet.features.libshadow? + if ent = Shadow::Passwd.getspnam(@resource.name) + return ent.sp_max + end + end + :absent + end + # Retrieve the password using the Shadow Password library def password if Puppet.features.libshadow? diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb index 414b1bc18..74805bb6f 100644 --- a/lib/puppet/rails.rb +++ b/lib/puppet/rails.rb @@ -2,6 +2,7 @@ require 'facter' require 'puppet' +require 'logger' module Puppet::Rails TIME_DEBUG = true @@ -22,9 +23,8 @@ module Puppet::Rails ActiveRecord::Base.logger.level = Logger::DEBUG end - if (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1) - ActiveRecord::Base.allow_concurrency = true - end + # As of ActiveRecord 2.2 allow_concurrency has been deprecated and no longer has any effect. + ActiveRecord::Base.allow_concurrency = true if Puppet::Util.activerecord_version < 2.2 ActiveRecord::Base.verify_active_connections! @@ -52,21 +52,17 @@ module Puppet::Rails args[:port] = Puppet[:dbport] unless Puppet[:dbport].to_s.empty? args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty? args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty? + args[:pool] = Puppet[:dbconnections].to_i unless Puppet[:dbconnections].to_i <= 0 args[:database] = Puppet[:dbname] args[:reconnect]= true socket = Puppet[:dbsocket] args[:socket] = socket unless socket.to_s.empty? - - connections = Puppet[:dbconnections].to_i - args[:pool] = connections if connections > 0 when "oracle_enhanced": args[:database] = Puppet[:dbname] unless Puppet[:dbname].to_s.empty? args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty? args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty? - - connections = Puppet[:dbconnections].to_i - args[:pool] = connections if connections > 0 + args[:pool] = Puppet[:dbconnections].to_i unless Puppet[:dbconnections].to_i <= 0 else raise ArgumentError, "Invalid db adapter #{adapter}" end diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb index 986cebd0a..b9dea2a3d 100644 --- a/lib/puppet/rails/host.rb +++ b/lib/puppet/rails/host.rb @@ -16,16 +16,6 @@ class Puppet::Rails::Host < ActiveRecord::Base belongs_to :source_file has_many :resources, :dependent => :destroy, :class_name => "Puppet::Rails::Resource" - # If the host already exists, get rid of its objects - def self.clean(host) - if obj = self.find_by_name(host) - obj.rails_objects.clear - return obj - else - return nil - end - end - def self.from_puppet(node) host = find_by_name(node.name) || new(:name => node.name) @@ -38,63 +28,6 @@ class Puppet::Rails::Host < ActiveRecord::Base host end - # Store our host in the database. - def self.store(node, resources) - args = {} - - host = nil - railsmark "Stored node" do - transaction do - #unless host = find_by_name(name) - - debug_benchmark("Searched for host")do - unless host = find_by_name(node.name) - host = new(:name => node.name) - end - end - if ip = node.parameters["ipaddress"] - host.ip = ip - end - - if env = node.environment - host.environment = env - end - - # Store the facts into the database. - host.merge_facts(node.parameters) - - debug_benchmark("Handled resources") { - host.merge_resources(resources) - } - - host.last_compile = Time.now - - debug_benchmark("Saved host") { - host.save - } - end - - end - - # This only runs if time debugging is enabled. - write_benchmarks - - host - end - - # Return the value of a fact. - def fact(name) - - if fv = self.fact_values.find( - :all, :include => :fact_name, - - :conditions => "fact_names.name = '#{name}'") - return fv - else - return nil - end - end - # returns a hash of fact_names.name => [ fact_values ] for this host. # Note that 'fact_values' is actually a list of the value instances, not # just actual values. @@ -305,11 +238,6 @@ class Puppet::Rails::Host < ActiveRecord::Base end end - def update_connect_time - self.last_connect = Time.now - save - end - def to_puppet node = Puppet::Node.new(self.name) {"ip" => "ipaddress", "environment" => "environment"}.each do |myparam, itsparam| diff --git a/lib/puppet/reference/configuration.rb b/lib/puppet/reference/configuration.rb index bfa2cb802..e6a8dc20f 100644 --- a/lib/puppet/reference/configuration.rb +++ b/lib/puppet/reference/configuration.rb @@ -33,7 +33,7 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc # Leave out the section information; it was apparently confusing people. #str += "- **Section**: #{object.section}\n" unless val == "" - str += "- **Default**: #{val}\n" + str += "- *Default*: #{val}\n" end str += "\n" end @@ -42,12 +42,11 @@ config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc end config.header = " -Specifying Configuration Parameters ------------------------------------ +## Specifying Configuration Parameters -On The Command-Line -+++++++++++++++++++ -Every Puppet executable (with the exception of ``puppetdoc``) accepts all of +### On The Command-Line + +Every Puppet executable (with the exception of `puppetdoc`) accepts all of the parameters below, but not all of the arguments make sense for every executable. I have tried to be as thorough as possible in the descriptions of the @@ -55,60 +54,59 @@ arguments, so it should be obvious whether an argument is appropriate or not. These parameters can be supplied to the executables either as command-line options or in the configuration file. For instance, the command-line -invocation below would set the configuration directory to ``/private/puppet``:: +invocation below would set the configuration directory to `/private/puppet`: - $ puppet agent --confdir=/private/puppet + $ puppet agent --confdir=/private/puppet Note that boolean options are turned on and off with a slightly different -syntax on the command line:: +syntax on the command line: - $ puppet agent --storeconfigs + $ puppet agent --storeconfigs - $ puppet agent --no-storeconfigs + $ puppet agent --no-storeconfigs The invocations above will enable and disable, respectively, the storage of the client configuration. -Configuration Files -+++++++++++++++++++ +### Configuration Files + As mentioned above, the configuration parameters can also be stored in a configuration file, located in the configuration directory. As root, the -default configuration directory is ``/etc/puppet``, and as a regular user, the -default configuration directory is ``~user/.puppet``. As of 0.23.0, all -executables look for ``puppet.conf`` in their configuration directory +default configuration directory is `/etc/puppet`, and as a regular user, the +default configuration directory is `~user/.puppet`. As of 0.23.0, all +executables look for `puppet.conf` in their configuration directory (although they previously looked for separate files). For example, -``puppet.conf`` is located at ``/etc/puppet/puppet.conf`` as root and -``~user/.puppet/puppet.conf`` as a regular user by default. +`puppet.conf` is located at `/etc/puppet/puppet.conf` as `root` and +`~user/.puppet/puppet.conf` as a regular user by default. + +All executables will set any parameters set within the `[main]` section, +and each executable will also use one of the `[master]`, `[agent]`. -All executables will set any parameters set within the ``main`` section, -and each executable will also use one of the ``master``, ``agent``, or -``user`` sections. +#### File Format -File Format -''''''''''' The file follows INI-style formatting. Here is an example of a very simple -``puppet.conf`` file:: +`puppet.conf` file: - [main] - confdir = /private/puppet - storeconfigs = true + [main] + confdir = /private/puppet + storeconfigs = true Note that boolean parameters must be explicitly specified as `true` or `false` as seen above. If you need to change file parameters (e.g., reset the mode or owner), do -so within curly braces on the same line:: +so within curly braces on the same line: - [main] - myfile = /tmp/whatever {owner = root, mode = 644} + [main] + myfile = /tmp/whatever {owner = root, mode = 644} If you're starting out with a fresh configuration, you may wish to let the executable generate a template configuration file for you by invoking the executable in question with the `--genconfig` command. The executable will print a template configuration to standard output, which can be -redirected to a file like so:: +redirected to a file like so: - $ puppet agent --genconfig > /etc/puppet/puppet.conf + $ puppet agent --genconfig > /etc/puppet/puppet.conf Note that this invocation will replace the contents of any pre-existing `puppet.conf` file, so make a backup of your present config if it contains @@ -117,28 +115,28 @@ valuable information. Like the `--genconfig` argument, the executables also accept a `--genmanifest` argument, which will generate a manifest that can be used to manage all of Puppet's directories and files and prints it to standard output. This can -likewise be redirected to a file:: +likewise be redirected to a file: - $ puppet agent --genmanifest > /etc/puppet/manifests/site.pp + $ puppet agent --genmanifest > /etc/puppet/manifests/site.pp Puppet can also create user and group accounts for itself (one `puppet` group -and one `puppet` user) if it is invoked as `root` with the `--mkusers` argument:: +and one `puppet` user) if it is invoked as `root` with the `--mkusers` argument: - $ puppet agent --mkusers + $ puppet agent --mkusers -Signals -------- -The ``puppet agent`` and ``puppet master`` executables catch some signals for special -handling. Both daemons catch (``SIGHUP``), which forces the server to restart -tself. Predictably, interrupt and terminate (``SIGINT`` and ``SIGTERM``) will shut -down the server, whether it be an instance of ``puppet agent`` or ``puppet master``. +## Signals -Sending the ``SIGUSR1`` signal to an instance of ``puppet agent`` will cause it to +The `puppet agent` and `puppet master` executables catch some signals for special +handling. Both daemons catch (`SIGHUP`), which forces the server to restart +tself. Predictably, interrupt and terminate (`SIGINT` and `SIGTERM`) will shut +down the server, whether it be an instance of `puppet agent` or `puppet master`. + +Sending the `SIGUSR1` signal to an instance of `puppet agent` will cause it to immediately begin a new configuration transaction with the server. This -signal has no effect on ``puppet master``. +signal has no effect on `puppet master`. + +## Configuration Parameter Reference -Configuration Parameter Reference ---------------------------------- Below is a list of all documented parameters. Not all of them are valid with all Puppet executables, but the executables will ignore any inappropriate values. diff --git a/lib/puppet/reference/indirection.rb b/lib/puppet/reference/indirection.rb index d14510c16..e5b076508 100644 --- a/lib/puppet/reference/indirection.rb +++ b/lib/puppet/reference/indirection.rb @@ -8,12 +8,12 @@ reference = Puppet::Util::Reference.newreference :indirection, :doc => "Indirect Puppet::Indirector::Indirection.instances.sort { |a,b| a.to_s <=> b.to_s }.each do |indirection| ind = Puppet::Indirector::Indirection.instance(indirection) name = indirection.to_s.capitalize - text += indirection.to_s + "\n" + ("-" * name.length) + "\n\n" + text += "## " + indirection.to_s + "\n\n" text += ind.doc + "\n\n" Puppet::Indirector::Terminus.terminus_classes(ind.name).sort { |a,b| a.to_s <=> b.to_s }.each do |terminus| - text += terminus.to_s + "\n" + ("+" * terminus.to_s.length) + "\n\n" + text += "### " + terminus.to_s + "\n\n" term_class = Puppet::Indirector::Terminus.terminus_class(ind.name, terminus) @@ -26,9 +26,8 @@ end reference.header = "This is the list of all indirections, their associated terminus classes, and how you select between them. -In general, the appropriate terminus class is selected by the application for you (e.g., ``puppet agent`` would always use the ``rest`` -terminus for most of its indirected classes), but some classes are tunable via normal settings. These will have ``terminus setting`` -documentation listed with them. +In general, the appropriate terminus class is selected by the application for you (e.g., `puppet agent` would always use the `rest` +terminus for most of its indirected classes), but some classes are tunable via normal settings. These will have `terminus setting` documentation listed with them. " diff --git a/lib/puppet/reference/metaparameter.rb b/lib/puppet/reference/metaparameter.rb index 6a319f1c2..c16a1d33a 100644 --- a/lib/puppet/reference/metaparameter.rb +++ b/lib/puppet/reference/metaparameter.rb @@ -9,16 +9,17 @@ metaparameter = Puppet::Util::Reference.newreference :metaparameter, :doc => "Al } str = %{ - Metaparameters - -------------- - Metaparameters are parameters that work with any resource type; they are part of the - Puppet framework itself rather than being part of the implementation of any - given instance. Thus, any defined metaparameter can be used with any instance - in your manifest, including defined components. - Available Metaparameters - ++++++++++++++++++++++++ - } +# Metaparameters + +Metaparameters are parameters that work with any resource type; they are part of the +Puppet framework itself rather than being part of the implementation of any +given instance. Thus, any defined metaparameter can be used with any instance +in your manifest, including defined components. + +## Available Metaparameters + +} begin params = [] Puppet::Type.eachmetaparam { |param| @@ -29,14 +30,6 @@ metaparameter = Puppet::Util::Reference.newreference :metaparameter, :doc => "Al a.to_s <=> b.to_s }.each { |param| str += paramwrap(param.to_s, scrub(Puppet::Type.metaparamdoc(param)), :level => 4) - #puts "<dt>#{param}</dt>" - #puts tab(1) + Puppet::Type.metaparamdoc(param).scrub.indent($tab)gsub(/\n\s*/,' ') - #puts "<dd>" - #puts indent(scrub(Puppet::Type.metaparamdoc(param)), $tab) - #puts scrub(Puppet::Type.metaparamdoc(param)) - #puts "</dd>" - - #puts "" } rescue => detail puts detail.backtrace diff --git a/lib/puppet/reference/network.rb b/lib/puppet/reference/network.rb index 15e4f6769..fda7931fb 100644 --- a/lib/puppet/reference/network.rb +++ b/lib/puppet/reference/network.rb @@ -29,11 +29,11 @@ on the server, and the client knows how to call the handler's methods appropriately. Most handlers are meant to be started on the server, usually within -``puppet master``, and the clients are mostly started on the client, -usually within ``puppet agent``. +`puppet master`, and the clients are mostly started on the client, +usually within `puppet agent`. You can find the server-side handler for each interface at -``puppet/network/handler/<name>.rb`` and the client class at -``puppet/network/client/<name>.rb``. +`puppet/network/handler/<name>.rb` and the client class at +`puppet/network/client/<name>.rb`. " diff --git a/lib/puppet/reference/providers.rb b/lib/puppet/reference/providers.rb index ef33a559b..c85ad23ab 100644 --- a/lib/puppet/reference/providers.rb +++ b/lib/puppet/reference/providers.rb @@ -47,7 +47,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider # Add the suitability note if missing = provider.suitable?(false) and missing.empty? - data << "**X**" + data << "*X*" suit = true functional = true else @@ -86,7 +86,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider # Add a note for every feature features.each do |feature| if provider.features.include?(feature) - data << "**X**" + data << "*X*" else data << "" end @@ -95,7 +95,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider ret += h(type.name.to_s + "_", 2) - ret += ".. _#{type.name}: #{"http://docs.puppetlabs.com/references/stable/type.html##{type.name}"}\n\n" + ret += "[#{type.name}](#{"http://docs.puppetlabs.com/references/stable/type.html##{type.name}"})\n\n" ret += option("Default provider", default) ret += doctable(headers, table_data) @@ -111,7 +111,7 @@ providers = Puppet::Util::Reference.newreference :providers, :title => "Provider ret end providers.header = " -Puppet resource types are usually backed by multiple implementations called ``providers``, +Puppet resource types are usually backed by multiple implementations called `providers`, which handle variance between platforms and tools. Different providers are suitable or unsuitable on different platforms based on things diff --git a/lib/puppet/reference/report.rb b/lib/puppet/reference/report.rb index 481ca2dc1..47fc779ab 100644 --- a/lib/puppet/reference/report.rb +++ b/lib/puppet/reference/report.rb @@ -7,16 +7,15 @@ end report.header = " Puppet clients can report back to the server after each transaction. This transaction report is sent as a YAML dump of the -``Puppet::Transaction::Report`` class and includes every log message that was +`Puppet::Transaction::Report` class and includes every log message that was generated during the transaction along with as many metrics as Puppet knows how -to collect. See `ReportsAndReporting Reports and Reporting`:trac: -for more information on how to use reports. +to collect. See [Reports and Reporting](http://projects.puppetlabs.com/projects/puppet/wiki/Reports_And_Reporting) for more information on how to use reports. Currently, clients default to not sending in reports; you can enable reporting -by setting the ``report`` parameter to true. +by setting the `report` parameter to true. -To use a report, set the ``reports`` parameter on the server; multiple -reports must be comma-separated. You can also specify ``none`` to disable +To use a report, set the `reports` parameter on the server; multiple +reports must be comma-separated. You can also specify `none` to disable reports entirely. Puppet provides multiple report handlers that will process client reports: diff --git a/lib/puppet/reference/type.rb b/lib/puppet/reference/type.rb index be8742edc..b423387e9 100644 --- a/lib/puppet/reference/type.rb +++ b/lib/puppet/reference/type.rb @@ -5,34 +5,34 @@ type = Puppet::Util::Reference.newreference :type, :doc => "All Puppet resource Puppet::Type.eachtype { |type| next if type.name == :puppet next if type.name == :component + next if type.name == :whit types[type.name] = type } str = %{ - Resource Types - -------------- +## Resource Types - - The *namevar* is the parameter used to uniquely identify a type instance. +- The *namevar* is the parameter used to uniquely identify a type instance. This is the parameter that gets assigned when a string is provided before the colon in a type declaration. In general, only developers will need to - worry about which parameter is the ``namevar``. + worry about which parameter is the `namevar`. - In the following code:: + In the following code: - file { "/etc/passwd": - owner => root, - group => root, - mode => 644 - } + file { "/etc/passwd": + owner => root, + group => root, + mode => 644 + } - ``/etc/passwd`` is considered the title of the file object (used for things like - dependency handling), and because ``path`` is the namevar for ``file``, that - string is assigned to the ``path`` parameter. + `/etc/passwd` is considered the title of the file object (used for things like + dependency handling), and because `path` is the namevar for `file`, that + string is assigned to the `path` parameter. - *Parameters* determine the specific configuration of the instance. They either directly modify the system (internally, these are called properties) or they affect - how the instance behaves (e.g., adding a search path for ``exec`` instances or determining recursion on ``file`` instances). + how the instance behaves (e.g., adding a search path for `exec` instances or determining recursion on `file` instances). - *Providers* provide low-level functionality for a given resource type. This is usually in the form of calling out to external commands. diff --git a/lib/puppet/reports/http.rb b/lib/puppet/reports/http.rb index f1a74195d..7ac54dfbd 100644 --- a/lib/puppet/reports/http.rb +++ b/lib/puppet/reports/http.rb @@ -5,7 +5,7 @@ require 'uri' Puppet::Reports.register_report(:http) do desc <<-DESC - Send report information via HTTP to the ``reporturl``. Each host sends + Send report information via HTTP to the `reporturl`. Each host sends its report as a YAML dump and this sends this YAML to a client via HTTP POST. The YAML is the `report` parameter of the request." DESC diff --git a/lib/puppet/reports/rrdgraph.rb b/lib/puppet/reports/rrdgraph.rb index 9fbeb60e8..517fa8f03 100644 --- a/lib/puppet/reports/rrdgraph.rb +++ b/lib/puppet/reports/rrdgraph.rb @@ -1,12 +1,11 @@ Puppet::Reports.register_report(:rrdgraph) do desc "Graph all available data about hosts using the RRD library. You must have the Ruby RRDtool library installed to use this report, which - you can get from `the RubyRRDTool RubyForge page`_. This package may also - be available as ``ruby-rrd`` or ``rrdtool-ruby`` in your distribution's package - management system. The library and/or package will both require the binary - ``rrdtool`` package from your distribution to be installed. - - .. _the RubyRRDTool RubyForge page: http://rubyforge.org/projects/rubyrrdtool/ + you can get from + [the RubyRRDTool RubyForge page](http://rubyforge.org/projects/rubyrrdtool/). + This package may also be available as `ruby-rrd` or `rrdtool-ruby` in your + distribution's package management system. The library and/or package will both + require the binary `rrdtool` package from your distribution to be installed. This report will create, manage, and graph RRD database files for each of the metrics generated during transactions, and it will create a @@ -14,12 +13,12 @@ Puppet::Reports.register_report(:rrdgraph) do point, it will not create a common index file to display links to all hosts. - All RRD files and graphs get created in the ``rrddir`` directory. If + All RRD files and graphs get created in the `rrddir` directory. If you want to serve these publicly, you should be able to just alias that directory in a web server. - If you really know what you're doing, you can tune the ``rrdinterval``, - which defaults to the ``runinterval``." + If you really know what you're doing, you can tune the `rrdinterval`, + which defaults to the `runinterval`." def hostdir @hostdir ||= File.join(Puppet[:rrddir], self.host) @@ -123,7 +122,7 @@ Puppet::Reports.register_report(:rrdgraph) do # that means we record the total time, the config time, and that's about # it. We should probably send each type's time as a separate metric. def timeclean(metric) - metric.values = metric.values.find_all { |name, label, value| [:total, :config_retrieval].include?(name) } + metric.values = metric.values.find_all { |name, label, value| ['total', 'config_retrieval'].include?(name.to_s) } end end diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb index 65159fc07..30f24591c 100644 --- a/lib/puppet/reports/store.rb +++ b/lib/puppet/reports/store.rb @@ -2,7 +2,7 @@ require 'puppet' Puppet::Reports.register_report(:store) do desc "Store the yaml report on disk. Each host sends its report as a YAML dump - and this just stores the file on disk, in the ``reportdir`` directory. + and this just stores the file on disk, in the `reportdir` directory. These files collect quickly -- one every half hour -- so it is a good idea to perform some maintenance on them if you use this report (it's the only @@ -19,7 +19,7 @@ Puppet::Reports.register_report(:store) do :owner => 'service', :group => 'service' }, - + :noop => [false, "Used by settings internally."] ) diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb index 652104096..e17143e2f 100644 --- a/lib/puppet/reports/tagmail.rb +++ b/lib/puppet/reports/tagmail.rb @@ -6,12 +6,12 @@ require 'time' Puppet::Reports.register_report(:tagmail) do desc "This report sends specific log messages to specific email addresses - based on the tags in the log messages. See the - `UsingTags tag documentation`:trac: for more information - on tags. + based on the tags in the log messages. - To use this report, you must create a ``tagmail.conf`` (in the location - specified by ``tagmap``). This is a simple file that maps tags to + See the [UsingTags tag documentation](http://projects.puppetlabs.com/projects/puppet/wiki/Using_Tags) for more information on tags. + + To use this report, you must create a `tagmail.conf` (in the location + specified by `tagmap`). This is a simple file that maps tags to email addresses: Any log messages in the report that match the specified tags will be sent to the specified email addresses. @@ -20,21 +20,20 @@ Puppet::Reports.register_report(:tagmail) do the email addresses by a colon, and the email addresses should also be comma-separated. - Lastly, there is an ``all`` tag that will always match all log messages. + Lastly, there is an `all` tag that will always match all log messages. - Here is an example tagmail.conf:: + Here is an example `tagmail.conf`: - all: me@domain.com - webserver, !mailserver: httpadmins@domain.com + all: me@domain.com + webserver, !mailserver: httpadmins@domain.com - This will send all messages to ``me@domain.com``, and all messages from - webservers that are not also from mailservers to ``httpadmins@domain.com``. + This will send all messages to `me@domain.com`, and all messages from + webservers that are not also from mailservers to `httpadmins@domain.com`. If you are using anti-spam controls, such as grey-listing, on your mail - server you should whitelist the sending email (controlled by ``reportform`` configuration option) to ensure your email is not discarded as spam. + server you should whitelist the sending email (controlled by `reportform` configuration option) to ensure your email is not discarded as spam. " - # Find all matching messages. def match(taglists) matching_logs = [] @@ -85,7 +84,7 @@ Puppet::Reports.register_report(:tagmail) do pos = [] neg = [] taglist.sub(/\s+$/,'').split(/\s*,\s*/).each do |tag| - unless tag =~ /^!?[-\w]+$/ + unless tag =~ /^!?[-\w\.]+$/ raise ArgumentError, "Invalid tag #{tag.inspect}" end case tag diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb index 96d22e414..4f0d50750 100644 --- a/lib/puppet/resource.rb +++ b/lib/puppet/resource.rb @@ -13,7 +13,7 @@ class Puppet::Resource extend Puppet::Util::Pson include Enumerable attr_accessor :file, :line, :catalog, :exported, :virtual, :validate_parameters, :strict - attr_reader :namespaces + attr_reader :type, :title require 'puppet/indirector' extend Puppet::Indirector @@ -80,6 +80,18 @@ class Puppet::Resource end end + def yaml_property_munge(x) + case x + when Hash + x.inject({}) { |h,kv| + k,v = kv + h[k] = self.class.value_to_pson_data(v) + h + } + else self.class.value_to_pson_data(x) + end + end + def to_pson(*args) to_pson_data_hash.to_pson(*args) end @@ -154,33 +166,42 @@ class Puppet::Resource end end + # This stub class is only needed for serialization compatibility with 0.25.x + class Reference + attr_accessor :type,:title + def initialize(type,title) + @type,@title = type,title + end + end + # Create our resource. def initialize(type, title = nil, attributes = {}) @parameters = {} - @namespaces = [""] - # Set things like namespaces and strictness first. + # Set things like strictness first. attributes.each do |attr, value| next if attr == :parameters send(attr.to_s + "=", value) end - # We do namespaces first, and use tmp variables, so our title - # canonicalization works (i.e., namespaces are set and resource - # types can be looked up) - tmp_type, tmp_title = extract_type_and_title(type, title) - self.type = tmp_type - self.title = tmp_title + @type, @title = extract_type_and_title(type, title) + + @type = munge_type_name(@type) + + if @type == "Class" + @title = :main if @title == "" + @title = munge_type_name(@title) + end if params = attributes[:parameters] extract_parameters(params) end - resolve_type_and_title - tag(self.type) tag(self.title) if valid_tag?(self.title) + @reference = Reference.new(@type,@title) # for serialization compatibility with 0.25.x + raise ArgumentError, "Invalid resource type #{type}" if strict? and ! resource_type end @@ -193,17 +214,12 @@ class Puppet::Resource return(catalog ? catalog.resource(to_s) : nil) end - def title=(value) - @unresolved_title = value - @title = nil - end - def resource_type - @resource_type ||= case type - when "Class"; find_hostclass(title) - when "Node"; find_node(title) + case type + when "Class"; known_resource_types.hostclass(title == :main ? "" : title) + when "Node"; known_resource_types.node(title) else - find_resource_type(type) + Puppet::Type.type(type.to_s.downcase.to_sym) || known_resource_types.definition(type) end end @@ -314,28 +330,6 @@ class Puppet::Resource self end - # We have to lazy-evaluate this. - def title=(value) - @title = nil - @unresolved_title = value - end - - # We have to lazy-evaluate this. - def type=(value) - @type = nil - @unresolved_type = value || "Class" - end - - def title - resolve_type_and_title unless @title - @title - end - - def type - resolve_type_and_title unless @type - @type - end - def valid_parameter?(name) resource_type.valid_parameter?(name) end @@ -346,29 +340,6 @@ class Puppet::Resource private - def find_node(name) - known_resource_types.node(name) - end - - def find_hostclass(title) - name = title == :main ? "" : title - known_resource_types.find_hostclass(namespaces, name) - end - - def find_resource_type(type) - # It still works fine without the type == 'class' short-cut, but it is a lot slower. - return nil if ["class", "node"].include? type.to_s.downcase - find_builtin_resource_type(type) || find_defined_resource_type(type) - end - - def find_builtin_resource_type(type) - Puppet::Type.type(type.to_s.downcase.to_sym) - end - - def find_defined_resource_type(type) - known_resource_types.find_definition(namespaces, type.to_s.downcase) - end - # Produce a canonical method name. def parameter_name(param) param = param.to_s.downcase.to_sym @@ -378,10 +349,6 @@ class Puppet::Resource param end - def namespaces=(ns) - @namespaces = Array(ns) - end - # The namevar for our resource type. If the type doesn't exist, # always use :name. def namevar @@ -428,54 +395,9 @@ class Puppet::Resource value.to_s.split("::").collect { |s| s.capitalize }.join("::") end - # This is an annoyingly complicated method for resolving qualified - # types as necessary, and putting them in type or title attributes. - def resolve_type_and_title - if @unresolved_type - @type = resolve_type - @unresolved_type = nil - end - if @unresolved_title - @title = resolve_title - @unresolved_title = nil - end - end - - def resolve_type - case type = munge_type_name(@unresolved_type) - when "Class", "Node"; - type - else - # Otherwise, some kind of builtin or defined resource type - munge_type_name( (r = find_resource_type(type)) ? r.name : type) - end - end - - # This method only works if resolve_type was called first - def resolve_title - case @type - when "Node"; return @unresolved_title - when "Class"; - resolve_title_for_class(@unresolved_title) - else - @unresolved_title - end - end - - def resolve_title_for_class(title) - if title == "" or title == :main - return :main - end - - if klass = find_hostclass(title) - result = klass.name - end - munge_type_name(result || title) - end - def parse_title h = {} - type = find_resource_type(@type) + type = resource_type if type.respond_to? :title_patterns type.title_patterns.each { |regexp, symbols_and_lambdas| if captures = regexp.match(title.to_s) diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb index 4b4342d11..a8668d844 100644 --- a/lib/puppet/resource/catalog.rb +++ b/lib/puppet/resource/catalog.rb @@ -57,7 +57,7 @@ class Puppet::Resource::Catalog < Puppet::SimpleGraph end def title_key_for_ref( ref ) - ref =~ /^([\w:]+)\[(.*)\]$/m + ref =~ /^([-\w:]+)\[(.*)\]$/m [$1, $2] end diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index 85c0979c1..77824845d 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -13,8 +13,8 @@ class Puppet::Resource::Type RESOURCE_SUPERTYPES = [:hostclass, :node, :definition] - attr_accessor :file, :line, :doc, :code, :ruby_code, :parent, :resource_type_collection, :module_name - attr_reader :type, :namespace, :arguments, :behaves_like + attr_accessor :file, :line, :doc, :code, :ruby_code, :parent, :resource_type_collection + attr_reader :type, :namespace, :arguments, :behaves_like, :module_name RESOURCE_SUPERTYPES.each do |t| define_method("#{t}?") { self.type == t } @@ -69,6 +69,7 @@ class Puppet::Resource::Type end scope = subscope(scope, resource) unless resource.title == :main + scope.compiler.add_class(name) unless definition? set_resource_parameters(resource, scope) @@ -91,6 +92,8 @@ class Puppet::Resource::Type end set_arguments(options[:arguments]) + + @module_name = options[:module_name] end # This is only used for node names, and really only when the node name @@ -137,21 +140,15 @@ class Puppet::Resource::Type end end - # Make an instance of our resource type. This is only possible - # for those classes and nodes that don't have any arguments, and is - # only useful for things like the 'include' function. - def mk_plain_resource(scope) + # Make an instance of the resource type, and place it in the catalog + # if it isn't in the catalog already. This is only possible for + # classes and nodes. No parameters are be supplied--if this is a + # parameterized class, then all parameters take on their default + # values. + def ensure_in_catalog(scope) type == :definition and raise ArgumentError, "Cannot create resources for defined resource types" resource_type = type == :hostclass ? :class : :node - # Make sure our parent class has been evaluated, if we have one. - if parent - parent_resource = scope.catalog.resource(resource_type, parent) - unless parent_resource - parent_type(scope).mk_plain_resource(scope) - end - end - # Do nothing if the resource already exists; this makes sure we don't # get multiple copies of the class resource, which helps provide the # singleton nature of classes. @@ -160,11 +157,22 @@ class Puppet::Resource::Type end resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) + instantiate_resource(scope, resource) scope.compiler.add_resource(scope, resource) - scope.catalog.tag(*resource.tags) resource end + def instantiate_resource(scope, resource) + # Make sure our parent class has been evaluated, if we have one. + if parent && !scope.catalog.resource(resource.type, parent) + parent_type(scope).ensure_in_catalog(scope) + end + + if ['Class', 'Node'].include? resource.type + scope.catalog.tag(*resource.tags) + end + end + def name return @name unless @name.is_a?(Regexp) @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'') @@ -174,12 +182,29 @@ class Puppet::Resource::Type @name.is_a?(Regexp) end + # MQR TODO: + # + # The change(s) introduced by the fix for #4270 are mostly silly & should be + # removed, though we didn't realize it at the time. If it can be established/ + # ensured that nodes never call parent_type and that resource_types are always + # (as they should be) members of exactly one resource_type_collection the + # following method could / should be replaced with: + # + # def parent_type + # @parent_type ||= parent && ( + # resource_type_collection.find_or_load([name],parent,type.to_sym) || + # fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{resource_type_collection.environment}" + # ) + # end + # + # ...and then the rest of the changes around passing in scope reverted. + # def parent_type(scope = nil) return nil unless parent unless @parent_type raise "Must pass scope to parent_type when called first time" unless scope - unless @parent_type = scope.environment.known_resource_types.send("find_#{type}", scope.namespaces, parent) + unless @parent_type = scope.environment.known_resource_types.send("find_#{type}", [name], parent) fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type} in #{scope.environment}" end end @@ -215,8 +240,13 @@ class Puppet::Resource::Type resource[param] = value end - scope.setvar("title", resource.title) unless set.include? :title - scope.setvar("name", resource.name) unless set.include? :name + if @type == :hostclass + scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title + scope.setvar("name", resource.name.to_s.downcase ) unless set.include? :name + else + scope.setvar("title", resource.title ) unless set.include? :title + scope.setvar("name", resource.name ) unless set.include? :name + end scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) diff --git a/lib/puppet/resource/type_collection.rb b/lib/puppet/resource/type_collection.rb index 6a933362f..a96927613 100644 --- a/lib/puppet/resource/type_collection.rb +++ b/lib/puppet/resource/type_collection.rb @@ -19,6 +19,12 @@ class Puppet::Resource::TypeCollection @watched_files = {} end + def import_ast(ast, modname) + ast.instantiate(modname).each do |instance| + add(instance) + end + end + def <<(thing) add(thing) self @@ -92,50 +98,8 @@ class Puppet::Resource::TypeCollection @definitions[munge_name(name)] end - def find(namespaces, name, type) - #Array("") == [] for some reason - namespaces = [namespaces] unless namespaces.is_a?(Array) - - if r = find_fully_qualified(name, type) - return r - end - - namespaces.each do |namespace| - ary = namespace.split("::") - - while ary.length > 0 - tmp_namespace = ary.join("::") - if r = find_partially_qualified(tmp_namespace, name, type) - return r - end - - # Delete the second to last object, which reduces our namespace by one. - ary.pop - end - - if result = send(type, name) - return result - end - end - nil - end - - def find_or_load(namespaces, name, type) - name = name.downcase - namespaces = [namespaces] unless namespaces.is_a?(Array) - namespaces = namespaces.collect { |ns| ns.downcase } - - # This could be done in the load_until, but the knowledge seems to - # belong here. - if r = find(namespaces, name, type) - return r - end - - loader.load_until(namespaces, name) { find(namespaces, name, type) } - end - def find_node(namespaces, name) - find("", name, :node) + @nodes[munge_name(name)] end def find_hostclass(namespaces, name) @@ -152,23 +116,6 @@ class Puppet::Resource::TypeCollection end end - def perform_initial_import - parser = Puppet::Parser::Parser.new(environment) - if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != "" - parser.string = code - else - file = Puppet.settings.value(:manifest, environment.to_s) - return unless File.exist?(file) - parser.file = file - end - parser.parse - rescue => detail - msg = "Could not parse for environment #{environment}: #{detail}" - error = Puppet::Error.new(msg) - error.set_backtrace(detail.backtrace) - raise error - end - def stale? @watched_files.values.detect { |file| file.changed? } end @@ -197,12 +144,52 @@ class Puppet::Resource::TypeCollection private - def find_fully_qualified(name, type) - send(type, name.sub(/^::/, '')) + # Return a list of all possible fully-qualified names that might be + # meant by the given name, in the context of namespaces. + def resolve_namespaces(namespaces, name) + name = name.downcase + if name =~ /^::/ + # name is explicitly fully qualified, so just return it, sans + # initial "::". + return [name.sub(/^::/, '')] + end + if name == "" + # The name "" has special meaning--it always refers to a "main" + # hostclass which contains all toplevel resources. + return [""] + end + + namespaces = [namespaces] unless namespaces.is_a?(Array) + namespaces = namespaces.collect { |ns| ns.downcase } + + result = [] + namespaces.each do |namespace| + ary = namespace.split("::") + + # Search each namespace nesting in innermost-to-outermost order. + while ary.length > 0 + result << "#{ary.join("::")}::#{name}" + ary.pop + end + + # Finally, search the toplevel namespace. + result << name + end + + return result.uniq end - def find_partially_qualified(namespace, name, type) - send(type, [namespace, name].join("::")) + # Resolve namespaces and find the given object. Autoload it if + # necessary. + def find_or_load(namespaces, name, type) + resolve_namespaces(namespaces, name).each do |fqname| + if result = send(type, fqname) || loader.try_load_fqname(type, fqname) + return result + end + end + + # Nothing found. + return nil end def munge_name(name) diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb index 945b1beb3..6d153b46d 100644 --- a/lib/puppet/simple_graph.rb +++ b/lib/puppet/simple_graph.rb @@ -7,123 +7,45 @@ require 'set' # A hopefully-faster graph class to replace the use of GRATR. class Puppet::SimpleGraph - # An internal class for handling a vertex's edges. - class VertexWrapper - attr_accessor :in, :out, :vertex - - # Remove all references to everything. - def clear - @adjacencies[:in].clear - @adjacencies[:out].clear - @vertex = nil - end - - def initialize(vertex) - @vertex = vertex - @adjacencies = {:in => {}, :out => {}} - end - - # Find adjacent vertices or edges. - def adjacent(options) - direction = options[:direction] || :out - options[:type] ||= :vertices - - return send(direction.to_s + "_edges") if options[:type] == :edges - - @adjacencies[direction].keys.reject { |vertex| @adjacencies[direction][vertex].empty? } - end - - # Add an edge to our list. - def add_edge(direction, edge) - opposite_adjacencies(direction, edge) << edge - end - - # Return all known edges. - def edges - in_edges + out_edges - end - - # Test whether we share an edge with a given vertex. - def has_edge?(direction, vertex) - return(vertex_adjacencies(direction, vertex).length > 0 ? true : false) - end - - # Create methods for returning the degree and edges. - [:in, :out].each do |direction| - # LAK:NOTE If you decide to create methods for directly - # testing the degree, you'll have to get the values and flatten - # the results -- you might have duplicate edges, which can give - # a false impression of what the degree is. That's just - # as expensive as just getting the edge list, so I've decided - # to only add this method. - define_method("#{direction}_edges") do - @adjacencies[direction].values.inject([]) { |total, adjacent| total += adjacent.to_a; total } - end - end - - # The other vertex in the edge. - def other_vertex(direction, edge) - case direction - when :in; edge.source - else - edge.target - end - end - - # Remove an edge from our list. Assumes that we've already checked - # that the edge is valid. - def remove_edge(direction, edge) - opposite_adjacencies(direction, edge).delete(edge) - end - - def to_s - vertex.to_s - end - - private - - # These methods exist so we don't need a Hash with a default proc. - - # Look up the adjacencies for a vertex at the other end of an - # edge. - def opposite_adjacencies(direction, edge) - opposite_vertex = other_vertex(direction, edge) - vertex_adjacencies(direction, opposite_vertex) - end - - # Look up the adjacencies for a given vertex. - def vertex_adjacencies(direction, vertex) - @adjacencies[direction][vertex] ||= Set.new - @adjacencies[direction][vertex] - end - end - + # + # All public methods of this class must maintain (assume ^ ensure) the following invariants, where "=~=" means + # equiv. up to order: + # + # @in_to.keys =~= @out_to.keys =~= all vertices + # @in_to.values.collect { |x| x.values }.flatten =~= @out_from.values.collect { |x| x.values }.flatten =~= all edges + # @in_to[v1][v2] =~= @out_from[v2][v1] =~= all edges from v1 to v2 + # @in_to [v].keys =~= vertices with edges leading to v + # @out_from[v].keys =~= vertices with edges leading from v + # no operation may shed reference loops (for gc) + # recursive operation must scale with the depth of the spanning trees, or better (e.g. no recursion over the set + # of all vertices, etc.) + # + # This class is intended to be used with DAGs. However, if the + # graph has a cycle, it will not cause non-termination of any of the + # algorithms. The topsort method detects and reports cycles. + # def initialize - @vertices = {} - @edges = [] + @in_to = {} + @out_from = {} + @upstream_from = {} + @downstream_from = {} end # Clear our graph. def clear - @vertices.each { |vertex, wrapper| wrapper.clear } - @vertices.clear - @edges.clear - end - - # Which resources a given resource depends upon. - def dependents(resource) - tree_from_vertex(resource).keys + @in_to.clear + @out_from.clear + @upstream_from.clear + @downstream_from.clear end # Which resources depend upon the given resource. def dependencies(resource) - # Cache the reversal graph, because it's somewhat expensive - # to create. - @reversal ||= reversal - # Strangely, it's significantly faster to search a reversed - # tree in the :out direction than to search a normal tree - # in the :in direction. - @reversal.tree_from_vertex(resource, :out).keys + vertex?(resource) ? upstream_from_vertex(resource).keys : [] + end + + def dependents(resource) + vertex?(resource) ? downstream_from_vertex(resource).keys : [] end # Whether our graph is directed. Always true. Used to produce dot files. @@ -133,8 +55,7 @@ class Puppet::SimpleGraph # Determine all of the leaf nodes below a given vertex. def leaves(vertex, direction = :out) - tree = tree_from_vertex(vertex, direction) - l = tree.keys.find_all { |c| adjacent(c, :direction => direction).empty? } + tree_from_vertex(vertex, direction).keys.find_all { |c| adjacent(c, :direction => direction).empty? } end # Collect all of the edges that the passed events match. Returns @@ -149,9 +70,7 @@ class Puppet::SimpleGraph # Get all of the edges that this vertex should forward events # to, which is the same thing as saying all edges directly below # This vertex in the graph. - adjacent(source, :direction => :out, :type => :edges).find_all do |edge| - edge.match?(event.name) - end + @out_from[source].values.flatten.find_all { |edge| edge.match?(event.name) } end # Return a reversed version of this graph. @@ -159,20 +78,50 @@ class Puppet::SimpleGraph result = self.class.new vertices.each { |vertex| result.add_vertex(vertex) } edges.each do |edge| - newedge = edge.class.new(edge.target, edge.source, edge.label) - result.add_edge(newedge) + result.add_edge edge.class.new(edge.target, edge.source, edge.label) end result end # Return the size of the graph. def size - @vertices.length + vertices.size end - # Return the graph as an array. def to_a - @vertices.keys + vertices + end + + # Provide a topological sort with cycle reporting + def topsort_with_cycles + degree = {} + zeros = [] + result = [] + + # Collect each of our vertices, with the number of in-edges each has. + vertices.each do |v| + edges = @in_to[v].dup + zeros << v if edges.empty? + degree[v] = edges + end + + # Iterate over each 0-degree vertex, decrementing the degree of + # each of its out-edges. + while v = zeros.pop + result << v + @out_from[v].each { |v2,es| + degree[v2].delete(v) + zeros << v2 if degree[v2].empty? + } + end + + # If we have any vertices left with non-zero in-degrees, then we've found a cycle. + if cycles = degree.values.reject { |ns| ns.empty? } and cycles.length > 0 + message = cycles.collect { |edges| '('+edges.collect { |e| e.to_s }.join(", ")+')' }.join(", ") + raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz" + end + + result end # Provide a topological sort. @@ -182,26 +131,24 @@ class Puppet::SimpleGraph result = [] # Collect each of our vertices, with the number of in-edges each has. - @vertices.each do |name, wrapper| - edges = wrapper.in_edges - zeros << wrapper if edges.length == 0 - degree[wrapper.vertex] = edges + vertices.each do |v| + edges = @in_to[v] + zeros << v if edges.empty? + degree[v] = edges.length end # Iterate over each 0-degree vertex, decrementing the degree of # each of its out-edges. - while wrapper = zeros.pop - result << wrapper.vertex - wrapper.out_edges.each do |edge| - degree[edge.target].delete(edge) - zeros << @vertices[edge.target] if degree[edge.target].length == 0 - end + while v = zeros.pop + result << v + @out_from[v].each { |v2,es| + zeros << v2 if (degree[v2] -= 1) == 0 + } end # If we have any vertices left with non-zero in-degrees, then we've found a cycle. - if cycles = degree.find_all { |vertex, edges| edges.length > 0 } and cycles.length > 0 - message = cycles.collect { |vertex, edges| edges.collect { |e| e.to_s }.join(", ") }.join(", ") - raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz" + if cycles = degree.values.reject { |ns| ns == 0 } and cycles.length > 0 + topsort_with_cycles end result @@ -209,103 +156,80 @@ class Puppet::SimpleGraph # Add a new vertex to the graph. def add_vertex(vertex) - @reversal = nil - return false if vertex?(vertex) - setup_vertex(vertex) - true # don't return the VertexWrapper instance. + @in_to[vertex] ||= {} + @out_from[vertex] ||= {} end # Remove a vertex from the graph. - def remove_vertex!(vertex) - return nil unless vertex?(vertex) - @vertices[vertex].edges.each { |edge| remove_edge!(edge) } - @edges -= @vertices[vertex].edges - @vertices[vertex].clear - @vertices.delete(vertex) + def remove_vertex!(v) + return unless vertex?(v) + @upstream_from.clear + @downstream_from.clear + (@in_to[v].values+@out_from[v].values).flatten.each { |e| remove_edge!(e) } + @in_to.delete(v) + @out_from.delete(v) end # Test whether a given vertex is in the graph. - def vertex?(vertex) - @vertices.include?(vertex) + def vertex?(v) + @in_to.include?(v) end # Return a list of all vertices. def vertices - @vertices.keys + @in_to.keys end # Add a new edge. The graph user has to create the edge instance, # since they have to specify what kind of edge it is. - def add_edge(source, target = nil, label = nil) - @reversal = nil - if target - edge = Puppet::Relationship.new(source, target, label) - else - edge = source - end - [edge.source, edge.target].each { |vertex| setup_vertex(vertex) unless vertex?(vertex) } - @vertices[edge.source].add_edge :out, edge - @vertices[edge.target].add_edge :in, edge - @edges << edge - true + def add_edge(e,*a) + return add_relationship(e,*a) unless a.empty? + @upstream_from.clear + @downstream_from.clear + add_vertex(e.source) + add_vertex(e.target) + @in_to[ e.target][e.source] ||= []; @in_to[ e.target][e.source] |= [e] + @out_from[e.source][e.target] ||= []; @out_from[e.source][e.target] |= [e] end - # Find a matching edge. Note that this only finds the first edge, - # not all of them or whatever. - def edge(source, target) - @edges.each_with_index { |test_edge, index| return test_edge if test_edge.source == source and test_edge.target == target } + def add_relationship(source, target, label = nil) + add_edge Puppet::Relationship.new(source, target, label) end - def edge_label(source, target) - return nil unless edge = edge(source, target) - edge.label + # Find all matching edges. + def edges_between(source, target) + (@out_from[source] || {})[target] || [] end # Is there an edge between the two vertices? def edge?(source, target) - return false unless vertex?(source) and vertex?(target) - - @vertices[source].has_edge?(:out, target) + vertex?(source) and vertex?(target) and @out_from[source][target] end def edges - @edges.dup + @in_to.values.collect { |x| x.values }.flatten end - # Remove an edge from our graph. - def remove_edge!(edge) - @vertices[edge.source].remove_edge(:out, edge) - @vertices[edge.target].remove_edge(:in, edge) - - @edges.delete(edge) - nil + def each_edge + @in_to.each { |t,ns| ns.each { |s,es| es.each { |e| yield e }}} end - # Find adjacent edges. - def adjacent(vertex, options = {}) - return [] unless wrapper = @vertices[vertex] - wrapper.adjacent(options) + # Remove an edge from our graph. + def remove_edge!(e) + if edge?(e.source,e.target) + @upstream_from.clear + @downstream_from.clear + @in_to [e.target].delete e.source if (@in_to [e.target][e.source] -= [e]).empty? + @out_from[e.source].delete e.target if (@out_from[e.source][e.target] -= [e]).empty? + end end - private - - # An internal method that skips the validation, so we don't have - # duplicate validation calls. - def setup_vertex(vertex) - @vertices[vertex] = VertexWrapper.new(vertex) + # Find adjacent edges. + def adjacent(v, options = {}) + return [] unless ns = (options[:direction] == :in) ? @in_to[v] : @out_from[v] + (options[:type] == :edges) ? ns.values.flatten : ns.keys end - - public - -# # For some reason, unconnected vertices do not show up in -# # this graph. -# def to_jpg(path, name) -# gv = vertices -# Dir.chdir(path) do -# induced_subgraph(gv).write_to_graphic_file('jpg', name) -# end -# end - + # Take container information from another graph and use it # to replace any container vertices with their respective leaves. # This creates direct relationships where there were previously @@ -318,16 +242,15 @@ class Puppet::SimpleGraph # to container leaves, but that would result in many more # relationships. stage_class = Puppet::Type.type(:stage) + whit_class = Puppet::Type.type(:whit) containers = other.topsort.find_all { |v| (v.is_a?(type) or v.is_a?(stage_class)) and vertex?(v) } containers.each do |container| # Get the list of children from the other graph. children = other.adjacent(container, :direction => :out) - # Just remove the container if it's empty. - if children.empty? - remove_vertex!(container) - next - end + # MQR TODO: Luke suggests that it should be possible to refactor the system so that + # container nodes are retained, thus obviating the need for the whit. + children = [whit_class.new(:name => container.name, :catalog => other)] if children.empty? # First create new edges for each of the :in edges [:in, :out].each do |dir| @@ -382,6 +305,26 @@ class Puppet::SimpleGraph predecessor end + def downstream_from_vertex(v) + return @downstream_from[v] if @downstream_from[v] + result = @downstream_from[v] = {} + @out_from[v].keys.each do |node| + result[node] = 1 + result.update(downstream_from_vertex(node)) + end + result + end + + def upstream_from_vertex(v) + return @upstream_from[v] if @upstream_from[v] + result = @upstream_from[v] = {} + @in_to[v].keys.each do |node| + result[node] = 1 + result.update(upstream_from_vertex(node)) + end + result + end + # LAK:FIXME This is just a paste of the GRATR code with slight modifications. # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an @@ -423,18 +366,6 @@ class Puppet::SimpleGraph system('dotty', dotfile) end - # Use +dot+ to create a graphical representation of the graph. Returns the - # filename of the graphics file. - def write_to_graphic_file (fmt='png', dotfile='graph') - src = dotfile + '.dot' - dot = dotfile + '.' + fmt - - File.open(src, 'w') {|f| f << self.to_dot << "\n"} - - system( "dot -T#{fmt} #{src} -o #{dot}" ) - dot - end - # Produce the graph files if requested. def write_graph(name) return unless Puppet[:graph] @@ -446,4 +377,73 @@ class Puppet::SimpleGraph f.puts to_dot("name" => name.to_s.capitalize) } end + + # This flag may be set to true to use the new YAML serialzation + # format (where @vertices is a simple list of vertices rather than a + # list of VertexWrapper objects). Deserialization supports both + # formats regardless of the setting of this flag. + class << self + attr_accessor :use_new_yaml_format + end + self.use_new_yaml_format = false + + # Stub class to allow graphs to be represented in YAML using the old + # (version 2.6) format. + class VertexWrapper + attr_reader :vertex, :adjacencies + def initialize(vertex, adjacencies) + @vertex = vertex + @adjacencies = adjacencies + end + end + + # instance_variable_get is used by Object.to_zaml to get instance + # variables. Override it so that we can simulate the presence of + # instance variables @edges and @vertices for serialization. + def instance_variable_get(v) + case v.to_s + when '@edges' then + edges + when '@vertices' then + if self.class.use_new_yaml_format + vertices + else + result = {} + vertices.each do |vertex| + adjacencies = {} + [:in, :out].each do |direction| + adjacencies[direction] = {} + adjacent(vertex, :direction => direction, :type => :edges).each do |edge| + other_vertex = direction == :in ? edge.source : edge.target + (adjacencies[direction][other_vertex] ||= Set.new).add(edge) + end + end + result[vertex] = Puppet::SimpleGraph::VertexWrapper.new(vertex, adjacencies) + end + result + end + else + super(v) + end + end + + def to_yaml_properties + other_vars = instance_variables.reject { |v| %w{@in_to @out_from @upstream_from @downstream_from}.include?(v) } + (other_vars + %w{@vertices @edges}).sort.uniq + end + + def yaml_initialize(tag, var) + initialize() + vertices = var.delete('vertices') + edges = var.delete('edges') + if vertices.is_a?(Hash) + # Support old (2.6) format + vertices = vertices.keys + end + vertices.each { |v| add_vertex(v) } + edges.each { |e| add_edge(e) } + var.each do |varname, value| + instance_variable_set("@#{varname}", value) + end + end end diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb index e4d06a039..2f6cae3f5 100644 --- a/lib/puppet/ssl/certificate_request.rb +++ b/lib/puppet/ssl/certificate_request.rb @@ -29,7 +29,7 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base # Support either an actual SSL key, or a Puppet key. key = key.content if key.is_a?(Puppet::SSL::Key) - # If we're a CSR for the CA, then use the real certname, rather than the + # If we're a CSR for the CA, then use the real ca_name, rather than the # fake 'ca' name. This is mostly for backward compatibility with 0.24.x, # but it's also just a good idea. common_name = name == Puppet::SSL::CA_NAME ? Puppet.settings[:ca_name] : name diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb index 63e6b922a..f3321bd29 100644 --- a/lib/puppet/sslcertificates/ca.rb +++ b/lib/puppet/sslcertificates/ca.rb @@ -147,21 +147,19 @@ class Puppet::SSLCertificates::CA # Create the root certificate. def mkrootcert - # Make the root cert's name the FQDN of the host running the CA. - name = Facter["hostname"].value + # Make the root cert's name "Puppet CA: " plus the FQDN of the host running the CA. + name = "Puppet CA: #{Facter["hostname"].value}" if domain = Facter["domain"].value name += ".#{domain}" end - cert = Certificate.new( - + cert = Certificate.new( :name => name, :cert => @config[:cacert], :encrypt => @config[:capass], :key => @config[:cakey], :selfsign => true, :ttl => ttl, - :type => :ca ) @@ -241,19 +239,15 @@ class Puppet::SSLCertificates::CA f << "%04X" % (serial + 1) } - - newcert = Puppet::SSLCertificates.mkcert( - + newcert = Puppet::SSLCertificates.mkcert( :type => :server, :name => csr.subject, :ttl => ttl, :issuer => @cert, :serial => serial, - :publickey => csr.public_key ) - sign_with_key(newcert) self.storeclientcert(newcert) diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb index e6d1e0528..1d3091428 100644 --- a/lib/puppet/transaction/report.rb +++ b/lib/puppet/transaction/report.rb @@ -62,30 +62,49 @@ class Puppet::Transaction::Report host end - # Provide a summary of this report. + # Provide a human readable textual summary of this report. def summary + report = raw_summary + ret = "" + report.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |key| + ret += "#{Puppet::Util::Metric.labelize(key)}:\n" - @metrics.sort { |a,b| a[1].label <=> b[1].label }.each do |name, metric| - ret += "#{metric.label}:\n" - metric.values.sort { |a,b| + report[key].keys.sort { |a,b| # sort by label - if a[0] == :total + if a == :total 1 - elsif b[0] == :total + elsif b == :total -1 else - a[1] <=> b[1] + report[key][a].to_s <=> report[key][b].to_s end - }.each do |name, label, value| + }.each do |label| + value = report[key][label] next if value == 0 value = "%0.2f" % value if value.is_a?(Float) - ret += " %15s %s\n" % [label + ":", value] + ret += " %15s %s\n" % [Puppet::Util::Metric.labelize(label) + ":", value] end end ret end + # Provide a raw hash summary of this report. + def raw_summary + report = {} + + @metrics.each do |name, metric| + key = metric.name.to_s + report[key] = {} + metric.values.each do |name, label, value| + report[key][name.to_s] = value + end + report[key]["total"] = 0 unless key == "time" or report[key].include?("total") + end + (report["time"] ||= {})["last_run"] = Time.now.tv_sec + report + end + # Based on the contents of this report's metrics, compute a single number # that represents the report. The resulting number is a bitmask where # individual bits represent the presence of different metrics. @@ -103,7 +122,6 @@ class Puppet::Transaction::Report resource_statuses.each do |name, status| metrics[:total] += status.change_count if status.change_count end - add_metric(:changes, metrics) end @@ -124,7 +142,6 @@ class Puppet::Transaction::Report metrics[:total] = resource_statuses.length resource_statuses.each do |name, status| - Puppet::Resource::Status::STATES.each do |state| metrics[state] += 1 if status.send(state) end diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb index aace6a38a..29ec9a539 100644 --- a/lib/puppet/transaction/resource_harness.rb +++ b/lib/puppet/transaction/resource_harness.rb @@ -72,7 +72,7 @@ class Puppet::Transaction::ResourceHarness resource[param] = value audited << param else - resource.info "Storing newly-audited value #{current[param]} for #{param}" + resource.debug "Storing newly-audited value #{current[param]} for #{param}" cache(resource, param, current[param]) end end diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index c3855a400..1b6e7dcd7 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -410,13 +410,15 @@ class Type property = self.newattr(name) - begin - # make sure the parameter doesn't have any errors - property.value = value - rescue => detail - error = Puppet::Error.new("Parameter #{name} failed: #{detail}") - error.set_backtrace(detail.backtrace) - raise error + if property + begin + # make sure the parameter doesn't have any errors + property.value = value + rescue => detail + error = Puppet::Error.new("Parameter #{name} failed: #{detail}") + error.set_backtrace(detail.backtrace) + raise error + end end nil @@ -472,6 +474,12 @@ class Type raise Puppet::Error, "Resource type #{self.class.name} does not support parameter #{name}" end + if provider and ! provider.class.supports_parameter?(klass) + missing = klass.required_features.find_all { |f| ! provider.class.feature?(f) } + info "Provider %s does not support features %s; not managing attribute %s" % [provider.class.name, missing.join(", "), name] + return nil + end + return @parameters[name] if @parameters.include?(name) @parameters[name] = klass.new(:resource => self) @@ -933,16 +941,16 @@ class Type newmetaparam(:schedule) do desc "On what schedule the object should be managed. You must create a schedule object, and then reference the name of that object to use - that for your schedule:: + that for your schedule: - schedule { daily: - period => daily, - range => \"2-4\" - } + schedule { daily: + period => daily, + range => \"2-4\" + } - exec { \"/usr/bin/apt-get update\": - schedule => daily - } + exec { \"/usr/bin/apt-get update\": + schedule => daily + } The creation of the schedule object does not need to appear in the configuration before objects that use it." @@ -957,7 +965,7 @@ class Type the value, and any changes already get logged." validate do |list| - list = Array(list) + list = Array(list).collect {|p| p.to_sym} unless list == [:all] list.each do |param| next if @resource.class.validattr?(param) @@ -982,8 +990,8 @@ class Type end def properties_to_audit(list) - if list == :all - list = all_properties if list == :all + if !list.kind_of?(Array) && list.to_sym == :all + list = all_properties else list = Array(list).collect { |p| p.to_sym } end @@ -1020,40 +1028,40 @@ class Type newmetaparam(:alias) do desc "Creates an alias for the object. Puppet uses this internally when you - provide a symbolic name:: - - file { sshdconfig: - path => $operatingsystem ? { - solaris => \"/usr/local/etc/ssh/sshd_config\", - default => \"/etc/ssh/sshd_config\" - }, - source => \"...\" - } + provide a symbolic name: + + file { sshdconfig: + path => $operatingsystem ? { + solaris => \"/usr/local/etc/ssh/sshd_config\", + default => \"/etc/ssh/sshd_config\" + }, + source => \"...\" + } - service { sshd: - subscribe => file[sshdconfig] - } + service { sshd: + subscribe => File[sshdconfig] + } - When you use this feature, the parser sets ``sshdconfig`` as the name, + When you use this feature, the parser sets `sshdconfig` as the name, and the library sets that as an alias for the file so the dependency - lookup for ``sshd`` works. You can use this parameter yourself, + lookup for `sshd` works. You can use this parameter yourself, but note that only the library can use these aliases; for instance, - the following code will not work:: + the following code will not work: - file { \"/etc/ssh/sshd_config\": - owner => root, - group => root, - alias => sshdconfig - } + file { \"/etc/ssh/sshd_config\": + owner => root, + group => root, + alias => sshdconfig + } - file { sshdconfig: - mode => 644 - } + file { sshdconfig: + mode => 644 + } There's no way here for the Puppet parser to know that these two stanzas should be affecting the same file. - See the `LanguageTutorial language tutorial`:trac: for more information. + See the [Language Tutorial](http://docs.puppetlabs.com/guides/language_tutorial.html) for more information. " @@ -1083,9 +1091,9 @@ class Type be useful to add your own tags to a given resource. Tags are currently useful for things like applying a subset of a - host's configuration:: + host's configuration: - puppet agent --test --tags mytag + puppet agent --test --tags mytag This way, when you're testing a configuration you can run just the portion you're testing." @@ -1189,23 +1197,23 @@ class Type newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do desc "One or more objects that this object depends on. This is used purely for guaranteeing that changes to required objects - happen before the dependent object. For instance:: + happen before the dependent object. For instance: - # Create the destination directory before you copy things down - file { \"/usr/local/scripts\": - ensure => directory - } + # Create the destination directory before you copy things down + file { \"/usr/local/scripts\": + ensure => directory + } - file { \"/usr/local/scripts/myscript\": - source => \"puppet://server/module/myscript\", - mode => 755, - require => File[\"/usr/local/scripts\"] - } + file { \"/usr/local/scripts/myscript\": + source => \"puppet://server/module/myscript\", + mode => 755, + require => File[\"/usr/local/scripts\"] + } Multiple dependencies can be specified by providing a comma-seperated list - of resources, enclosed in square brackets:: + of resources, enclosed in square brackets: - require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ] + require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ] Note that Puppet will autorequire everything that it can, and there are hooks in place so that it's easy for resources to add new @@ -1219,10 +1227,10 @@ class Type Currently, exec resources will autorequire their CWD (if it is specified) plus any fully qualified paths that appear in the - command. For instance, if you had an ``exec`` command that ran - the ``myscript`` mentioned above, the above code that pulls the + command. For instance, if you had an `exec` command that ran + the `myscript` mentioned above, the above code that pulls the file down would be automatically listed as a requirement to the - ``exec`` code, so that you would always be running againts the + `exec` code, so that you would always be running againts the most recent version. " end @@ -1230,20 +1238,20 @@ class Type newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do desc "One or more objects that this object depends on. Changes in the subscribed to objects result in the dependent objects being - refreshed (e.g., a service will get restarted). For instance:: - - class nagios { - file { \"/etc/nagios/nagios.conf\": - source => \"puppet://server/module/nagios.conf\", - alias => nagconf # just to make things easier for me - } - service { nagios: - ensure => running, - subscribe => File[nagconf] + refreshed (e.g., a service will get restarted). For instance: + + class nagios { + file { \"/etc/nagios/nagios.conf\": + source => \"puppet://server/module/nagios.conf\", + alias => nagconf # just to make things easier for me + } + service { nagios: + ensure => running, + subscribe => File[nagconf] + } } - } - Currently the ``exec``, ``mount`` and ``service`` type support + Currently the `exec`, `mount` and `service` type support refreshing. " end @@ -1251,18 +1259,18 @@ class Type newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do desc %{This parameter is the opposite of **require** -- it guarantees that the specified object is applied later than the specifying - object:: + object: - file { "/var/nagios/configuration": - source => "...", - recurse => true, - before => Exec["nagios-rebuid"] - } + file { "/var/nagios/configuration": + source => "...", + recurse => true, + before => Exec["nagios-rebuid"] + } - exec { "nagios-rebuild": - command => "/usr/bin/make", - cwd => "/var/nagios/configuration" - } + exec { "nagios-rebuild": + command => "/usr/bin/make", + cwd => "/var/nagios/configuration" + } This will make sure all of the files are up to date before the make command is run.} @@ -1270,16 +1278,16 @@ class Type newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do desc %{This parameter is the opposite of **subscribe** -- it sends events - to the specified object:: + to the specified object: - file { "/etc/sshd_config": - source => "....", - notify => Service[sshd] - } + file { "/etc/sshd_config": + source => "....", + notify => Service[sshd] + } - service { sshd: - ensure => running - } + service { sshd: + ensure => running + } This will restart the sshd service if the sshd config file changes.} end @@ -1293,24 +1301,24 @@ class Type By default, all classes get directly added to the 'main' stage. You can create new stages as resources: - stage { [pre, post]: } + stage { [pre, post]: } To order stages, use standard relationships: - stage { pre: before => Stage[main] } + stage { pre: before => Stage[main] } Or use the new relationship syntax: - Stage[pre] -> Stage[main] -> Stage[post] + Stage[pre] -> Stage[main] -> Stage[post] Then use the new class parameters to specify a stage: - class { foo: stage => pre } + class { foo: stage => pre } Stages can only be set on classes, not individual resources. This will - fail:: + fail: - file { '/foo': stage => pre, ensure => file } + file { '/foo': stage => pre, ensure => file } } end diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb index 7fcfdd7a3..d29bda648 100644 --- a/lib/puppet/type/augeas.rb +++ b/lib/puppet/type/augeas.rb @@ -28,27 +28,28 @@ Puppet::Type.newtype(:augeas) do via the augeas tool. Requires: - - augeas to be installed (http://www.augeas.net) - - ruby-augeas bindings - Sample usage with a string:: + - augeas to be installed (http://www.augeas.net) + - ruby-augeas bindings - augeas{\"test1\" : - context => \"/files/etc/sysconfig/firstboot\", - changes => \"set RUN_FIRSTBOOT YES\", - onlyif => \"match other_value size > 0\", - } + Sample usage with a string: - Sample usage with an array and custom lenses:: + augeas{\"test1\" : + context => \"/files/etc/sysconfig/firstboot\", + changes => \"set RUN_FIRSTBOOT YES\", + onlyif => \"match other_value size > 0\", + } - augeas{\"jboss_conf\": - context => \"/files\", - changes => [ - \"set /etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress\", - \"set /etc/jbossas/jbossas.conf/JAVA_HOME /usr\" - ], - load_path => \"$/usr/share/jbossas/lenses\", - } + Sample usage with an array and custom lenses: + + augeas{\"jboss_conf\": + context => \"/files\", + changes => [ + \"set /etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress\", + \"set /etc/jbossas/jbossas.conf/JAVA_HOME /usr\" + ], + load_path => \"$/usr/share/jbossas/lenses\", + } " @@ -71,23 +72,23 @@ Puppet::Type.newtype(:augeas) do newparam (:onlyif) do desc "Optional augeas command and comparisons to control the execution of this type. - Supported onlyif syntax:: - - get [AUGEAS_PATH] [COMPARATOR] [STRING] - match [MATCH_PATH] size [COMPARATOR] [INT] - match [MATCH_PATH] include [STRING] - match [MATCH_PATH] not_include [STRING] - match [MATCH_PATH] == [AN_ARRAY] - match [MATCH_PATH] != [AN_ARRAY] - - where:: - - AUGEAS_PATH is a valid path scoped by the context - MATCH_PATH is a valid match synatx scoped by the context - COMPARATOR is in the set [> >= != == <= <] - STRING is a string - INT is a number - AN_ARRAY is in the form ['a string', 'another']" + Supported onlyif syntax: + + get [AUGEAS_PATH] [COMPARATOR] [STRING] + match [MATCH_PATH] size [COMPARATOR] [INT] + match [MATCH_PATH] include [STRING] + match [MATCH_PATH] not_include [STRING] + match [MATCH_PATH] == [AN_ARRAY] + match [MATCH_PATH] != [AN_ARRAY] + + where: + + AUGEAS_PATH is a valid path scoped by the context + MATCH_PATH is a valid match synatx scoped by the context + COMPARATOR is in the set [> >= != == <= <] + STRING is a string + INT is a number + AN_ARRAY is in the form ['a string', 'another']" defaultto "" end @@ -95,16 +96,14 @@ Puppet::Type.newtype(:augeas) do newparam(:changes) do desc "The changes which should be applied to the filesystem. This can be either a string which contains a command or an array of commands. - Commands supported are:: + Commands supported are: - set [PATH] [VALUE] Sets the value VALUE at loction PATH - rm [PATH] Removes the node at location PATH - remove [PATH] Synonym for rm - clear [PATH] Keeps the node at PATH, but removes the value. - ins [LABEL] [WHERE] [PATH] - Inserts an empty node LABEL either [WHERE={before|after}] PATH. - insert [LABEL] [WHERE] [PATH] - Synonym for ins + set [PATH] [VALUE] Sets the value VALUE at loction PATH + rm [PATH] Removes the node at location PATH + remove [PATH] Synonym for rm + clear [PATH] Keeps the node at PATH, but removes the value. + ins [LABEL] [WHERE] [PATH] Inserts an empty node LABEL either [WHERE={before|after}] PATH. + insert [LABEL] [WHERE] [PATH] Synonym for ins If the parameter 'context' is set that value is prepended to PATH" end @@ -136,11 +135,11 @@ Puppet::Type.newtype(:augeas) do end newparam(:lens) do - desc "Use a specific lens, e.g. 'Hosts.lns'. When this parameter is set, you must also set the incl parameter to indicate which file to load. Only that file will be loaded, which greatly speeds up execution of the type" + desc "Use a specific lens, e.g. `Hosts.lns`. When this parameter is set, you must also set the incl parameter to indicate which file to load. Only that file will be loaded, which greatly speeds up execution of the type" end newparam(:incl) do - desc "Load only a specific file, e.g. '/etc/hosts'. When this parameter is set, you must also set the lens parameter to indicate which lens to use." + desc "Load only a specific file, e.g. `/etc/hosts`. When this parameter is set, you must also set the lens parameter to indicate which lens to use." end validate do diff --git a/lib/puppet/type/computer.rb b/lib/puppet/type/computer.rb index 86a30be27..89a0692bf 100644 --- a/lib/puppet/type/computer.rb +++ b/lib/puppet/type/computer.rb @@ -10,7 +10,7 @@ Puppet::Type.newtype(:computer) do This provider only manages Computer objects in the local directory service domain, not in remote directories. - If you wish to manage /etc/hosts on Mac OS X, then simply use the host + If you wish to manage `/etc/hosts` file on Mac OS X, then simply use the host type as per other platforms. This type primarily exists to create localhost Computer objects that MCX @@ -31,7 +31,7 @@ Puppet::Type.newtype(:computer) do newproperty(:ensure, :parent => Puppet::Property::Ensure) do desc "Control the existences of this computer record. Set this attribute to - ``present`` to ensure the computer record exists. Set it to ``absent`` + `present` to ensure the computer record exists. Set it to `absent` to delete any computer records with this name" newvalue(:present) do provider.create diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb index b3f5e608d..76399d693 100755 --- a/lib/puppet/type/cron.rb +++ b/lib/puppet/type/cron.rb @@ -15,32 +15,32 @@ Puppet::Type.newtype(:cron) do association is made and synced to disk, you can then manage the job normally (e.g., change the schedule of the job). - Example:: - - cron { logrotate: - command => \"/usr/sbin/logrotate\", - user => root, - hour => 2, - minute => 0 - } - - Note that all cron values can be specified as an array of values:: - - cron { logrotate: - command => \"/usr/sbin/logrotate\", - user => root, - hour => [2, 4] - } - - Or using ranges, or the step syntax ``*/2`` (although there's no guarantee that - your ``cron`` daemon supports it):: - - cron { logrotate: - command => \"/usr/sbin/logrotate\", - user => root, - hour => ['2-4'], - minute => '*/10' - } + Example: + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => 2, + minute => 0 + } + + Note that all cron values can be specified as an array of values: + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => [2, 4] + } + + Or using ranges, or the step syntax `*/2` (although there's no guarantee that + your `cron` daemon supports it): + + cron { logrotate: + command => \"/usr/sbin/logrotate\", + user => root, + hour => ['2-4'], + minute => '*/10' + } " ensurable @@ -169,7 +169,7 @@ Puppet::Type.newtype(:cron) do end if value == "*" - return value + return :absent end return value unless self.class.boundaries @@ -206,7 +206,7 @@ Puppet::Type.newtype(:cron) do profile is not sourced when the command is run, so if the user's environment is desired it should be sourced manually. - All cron parameters support ``absent`` as a value; this will + All cron parameters support `absent` as a value; this will remove any existing values for that field." def retrieve @@ -230,7 +230,7 @@ Puppet::Type.newtype(:cron) do end newproperty(:special) do - desc "Special schedules only supported on FreeBSD." + desc "Special schedules" def specials %w{reboot yearly annually monthly weekly daily midnight hourly} @@ -293,7 +293,7 @@ Puppet::Type.newtype(:cron) do but will not associate them with a specific job. Settings should be specified exactly as they should appear in - the crontab, e.g., ``PATH=/bin:/usr/bin:/usr/sbin``." + the crontab, e.g., `PATH=/bin:/usr/bin:/usr/sbin`." validate do |value| unless value =~ /^\s*(\w+)\s*=\s*(.*)\s*$/ or value == :absent or value == "absent" diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index bfeaaad34..606888c75 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -6,51 +6,51 @@ module Puppet @doc = "Executes external commands. It is critical that all commands executed using this mechanism can be run multiple times without harm, i.e., they are *idempotent*. One useful way to create idempotent - commands is to use the checks like ``creates`` to avoid running the + commands is to use the checks like `creates` to avoid running the command unless some condition is met. - Note also that you can restrict an ``exec`` to only run when it receives - events by using the ``refreshonly`` parameter; this is a useful way to + Note also that you can restrict an `exec` to only run when it receives + events by using the `refreshonly` parameter; this is a useful way to have your configuration respond to events with arbitrary commands. - It is worth noting that ``exec`` is special, in that it is not - currently considered an error to have multiple ``exec`` instances + It is worth noting that `exec` is special, in that it is not + currently considered an error to have multiple `exec` instances with the same name. This was done purely because it had to be this way in order to get certain functionality, but it complicates things. - In particular, you will not be able to use ``exec`` instances that + In particular, you will not be able to use `exec` instances that share their commands with other instances as a dependency, since Puppet has no way of knowing which instance you mean. - For example:: + For example: - # defined in the production class - exec { \"make\": - cwd => \"/prod/build/dir\", - path => \"/usr/bin:/usr/sbin:/bin\" - } + # defined in the production class + exec { \"make\": + cwd => \"/prod/build/dir\", + path => \"/usr/bin:/usr/sbin:/bin\" + } - . etc. . + . etc. . - # defined in the test class - exec { \"make\": - cwd => \"/test/build/dir\", - path => \"/usr/bin:/usr/sbin:/bin\" - } + # defined in the test class + exec { \"make\": + cwd => \"/test/build/dir\", + path => \"/usr/bin:/usr/sbin:/bin\" + } Any other type would throw an error, complaining that you had the same instance being managed in multiple places, but these are - obviously different images, so ``exec`` had to be treated specially. + obviously different images, so `exec` had to be treated specially. It is recommended to avoid duplicate names whenever possible. - Note that if an ``exec`` receives an event from another resource, - it will get executed again (or execute the command specified in ``refresh``, if there is one). + Note that if an `exec` receives an event from another resource, + it will get executed again (or execute the command specified in `refresh`, if there is one). - There is a strong tendency to use ``exec`` to do whatever work Puppet + There is a strong tendency to use `exec` to do whatever work Puppet can't already do; while this is obviously acceptable (and unavoidable) - in the short term, it is highly recommended to migrate work from ``exec`` + in the short term, it is highly recommended to migrate work from `exec` to native Puppet types as quickly as possible. If you find that - you are doing a lot of work with ``exec``, please at least notify + you are doing a lot of work with `exec`, please at least notify us at Puppet Labs what you are doing, and hopefully we can work with you to get a native resource type for the work you are doing." @@ -159,9 +159,9 @@ module Puppet desc "The actual command to execute. Must either be fully qualified or a search path for the command must be provided. If the command succeeds, any output produced will be logged at the instance's - normal log level (usually ``notice``), but if the command fails + normal log level (usually `notice`), but if the command fails (meaning its return code does not match the specified code) then - any output is logged at the ``err`` log level." + any output is logged at the `err` log level." end newparam(:path) do @@ -223,7 +223,7 @@ module Puppet newparam(:logoutput) do desc "Whether to log output. Defaults to logging output at the - loglevel for the ``exec`` resource. Use *on_failure* to only + loglevel for the `exec` resource. Use *on_failure* to only log the output when the command reports an error. Values are **true**, *false*, *on_failure*, and any legal log level." @@ -253,7 +253,7 @@ module Puppet newparam(:environment) do desc "Any additional environment variables you want to set for a command. Note that if you use this to set PATH, it will override - the ``path`` attribute. Multiple environment variables should be + the `path` attribute. Multiple environment variables should be specified as an array." validate do |values| @@ -330,22 +330,22 @@ module Puppet desc "The command should only be run as a refresh mechanism for when a dependent object is changed. It only makes sense to use this option when this command depends on some - other object; it is useful for triggering an action:: - - # Pull down the main aliases file - file { \"/etc/aliases\": - source => \"puppet://server/module/aliases\" - } - - # Rebuild the database, but only when the file changes - exec { newaliases: - path => [\"/usr/bin\", \"/usr/sbin\"], - subscribe => File[\"/etc/aliases\"], - refreshonly => true - } + other object; it is useful for triggering an action: + + # Pull down the main aliases file + file { \"/etc/aliases\": + source => \"puppet://server/module/aliases\" + } + + # Rebuild the database, but only when the file changes + exec { newaliases: + path => [\"/usr/bin\", \"/usr/sbin\"], + subscribe => File[\"/etc/aliases\"], + refreshonly => true + } - Note that only ``subscribe`` and ``notify`` can trigger actions, not ``require``, - so it only makes sense to use ``refreshonly`` with ``subscribe`` or ``notify``." + Note that only `subscribe` and `notify` can trigger actions, not `require`, + so it only makes sense to use `refreshonly` with `subscribe` or `notify`." newvalues(:true, :false) @@ -364,13 +364,13 @@ module Puppet newcheck(:creates) do desc "A file that this command creates. If this parameter is provided, then the command will only be run - if the specified file does not exist:: + if the specified file does not exist: - exec { \"tar xf /my/tar/file.tar\": - cwd => \"/var/tmp\", - creates => \"/var/tmp/myfile\", - path => [\"/usr/bin\", \"/usr/sbin\"] - } + exec { \"tar xf /my/tar/file.tar\": + cwd => \"/var/tmp\", + creates => \"/var/tmp/myfile\", + path => [\"/usr/bin\", \"/usr/sbin\"] + } " @@ -396,16 +396,16 @@ module Puppet end newcheck(:unless) do - desc "If this parameter is set, then this ``exec`` will run unless - the command returns 0. For example:: + desc "If this parameter is set, then this `exec` will run unless + the command returns 0. For example: - exec { \"/bin/echo root >> /usr/lib/cron/cron.allow\": - path => \"/usr/bin:/usr/sbin:/bin\", - unless => \"grep root /usr/lib/cron/cron.allow 2>/dev/null\" - } + exec { \"/bin/echo root >> /usr/lib/cron/cron.allow\": + path => \"/usr/bin:/usr/sbin:/bin\", + unless => \"grep root /usr/lib/cron/cron.allow 2>/dev/null\" + } - This would add ``root`` to the cron.allow file (on Solaris) unless - ``grep`` determines it's already there. + This would add `root` to the cron.allow file (on Solaris) unless + `grep` determines it's already there. Note that this command follows the same rules as the main command, which is to say that it must be fully qualified if the path is not set. @@ -433,22 +433,22 @@ module Puppet end newcheck(:onlyif) do - desc "If this parameter is set, then this ``exec`` will only run if - the command returns 0. For example:: + desc "If this parameter is set, then this `exec` will only run if + the command returns 0. For example: - exec { \"logrotate\": - path => \"/usr/bin:/usr/sbin:/bin\", - onlyif => \"test `du /var/log/messages | cut -f1` -gt 100000\" - } + exec { \"logrotate\": + path => \"/usr/bin:/usr/sbin:/bin\", + onlyif => \"test `du /var/log/messages | cut -f1` -gt 100000\" + } - This would run ``logrotate`` only if that test returned true. + This would run `logrotate` only if that test returned true. Note that this command follows the same rules as the main command, which is to say that it must be fully qualified if the path is not set. - Also note that onlyif can take an array as its value, eg:: + Also note that onlyif can take an array as its value, e.g.: - onlyif => [\"test -f /tmp/file1\", \"test -f /tmp/file2\"] + onlyif => [\"test -f /tmp/file1\", \"test -f /tmp/file2\"] This will only run the exec if /all/ conditions in the array return true. " @@ -553,13 +553,7 @@ module Puppet if self[:path] if Puppet.features.posix? and !File.exists?(exe) withenv :PATH => self[:path].join(File::PATH_SEPARATOR) do - path = %x{which #{exe}}.chomp - if path == "" - raise ArgumentError, - "Could not find command '#{exe}'" - else - exe = path - end + exe = which(exe) || raise(ArgumentError,"Could not find command '#{exe}'") end elsif Puppet.features.microsoft_windows? and !File.exists?(exe) self[:path].each do |path| @@ -683,4 +677,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb index 71f2756bc..f35a26408 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -16,7 +16,7 @@ Puppet::Type.newtype(:file) do @doc = "Manages local files, including setting ownership and permissions, creation of both files and directories, and retrieving entire files from remote servers. As Puppet matures, it - expected that the ``file`` resource will be used less and less to + expected that the `file` resource will be used less and less to manage content, and instead native resources will be used to do so. If you find that you are often copying files in from a central @@ -61,33 +61,33 @@ Puppet::Type.newtype(:file) do newparam(:backup) do desc "Whether files should be backed up before being replaced. The preferred method of backing files up is via - a ``filebucket``, which stores files by their MD5 sums and allows + a `filebucket`, which stores files by their MD5 sums and allows easy retrieval without littering directories with backups. You can specify a local filebucket or a network-accessible - server-based filebucket by setting ``backup => bucket-name``. - Alternatively, if you specify any value that begins with a ``.`` - (e.g., ``.puppet-bak``), then Puppet will use copy the file in + server-based filebucket by setting `backup => bucket-name`. + Alternatively, if you specify any value that begins with a `.` + (e.g., `.puppet-bak`), then Puppet will use copy the file in the same directory with that value as the extension of the - backup. Setting ``backup => false`` disables all backups of the + backup. Setting `backup => false` disables all backups of the file in question. - Puppet automatically creates a local filebucket named ``puppet`` and + Puppet automatically creates a local filebucket named `puppet` and defaults to backing up there. To use a server-based filebucket, - you must specify one in your configuration:: + you must specify one in your configuration - filebucket { main: - server => puppet - } + filebucket { main: + server => puppet + } - The ``puppet master`` daemon creates a filebucket by default, + The `puppet master` daemon creates a filebucket by default, so you can usually back up to your main server with this configuration. Once you've described the bucket in your - configuration, you can use it in any file:: + configuration, you can use it in any file - file { \"/my/file\": - source => \"/path/in/nfs/or/something\", - backup => main - } + file { \"/my/file\": + source => \"/path/in/nfs/or/something\", + backup => main + } This will back the file up to the central server. @@ -192,9 +192,9 @@ Puppet::Type.newtype(:file) do newparam(:ignore) do desc "A parameter which omits action on files matching specified patterns during recursion. Uses Ruby's builtin globbing - engine, so shell metacharacters are fully supported, e.g. ``[a-z]*``. + engine, so shell metacharacters are fully supported, e.g. `[a-z]*`. Matches that would descend into the directory structure are ignored, - e.g., ``*/*``." + e.g., `*/*`." validate do |value| unless value.is_a?(Array) or value.is_a?(String) or value == false @@ -205,10 +205,10 @@ Puppet::Type.newtype(:file) do newparam(:links) do desc "How to handle links during file actions. During file copying, - ``follow`` will copy the target file instead of the link, ``manage`` - will copy the link itself, and ``ignore`` will just pass it by. - When not copying, ``manage`` and ``ignore`` behave equivalently - (because you cannot really ignore links entirely during local recursion), and ``follow`` will manage the file to which the + `follow` will copy the target file instead of the link, `manage` + will copy the link itself, and `ignore` will just pass it by. + When not copying, `manage` and `ignore` behave equivalently + (because you cannot really ignore links entirely during local recursion), and `follow` will manage the file to which the link points." newvalues(:follow, :manage) @@ -223,7 +223,7 @@ Puppet::Type.newtype(:file) do files unless you really know what you are doing. This option only makes sense when recursively managing directories. - Note that when using ``purge`` with ``source``, Puppet will purge any files + Note that when using `purge` with `source`, Puppet will purge any files that are not on the remote system." defaultto :false @@ -234,7 +234,7 @@ Puppet::Type.newtype(:file) do newparam(:sourceselect) do desc "Whether to copy all valid sources, or just the first one. This parameter is only used in recursive copies; by default, the first valid source is the - only one used as a recursive source, but if this parameter is set to ``all``, + only one used as a recursive source, but if this parameter is set to `all`, then all valid sources will have all of their contents copied to the local host, and for sources that have the same file, the source earlier in the list will be used." diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb index 74b380f55..b8f30a9c7 100755 --- a/lib/puppet/type/file/content.rb +++ b/lib/puppet/type/file/content.rb @@ -161,11 +161,17 @@ module Puppet } end + def self.standalone? + Puppet.settings[:name] == "apply" + end + def each_chunk_from(source_or_content) if source_or_content.is_a?(String) yield source_or_content elsif source_or_content.nil? yield read_file_from_filebucket + elsif self.class.standalone? + yield source_or_content.content elsif source_or_content.local? chunk_file_from_disk(source_or_content) { |chunk| yield chunk } else @@ -184,7 +190,7 @@ module Puppet end def chunk_file_from_source(source_or_content) - request = Puppet::Indirector::Request.new(:file_content, :find, source_or_content.full_path) + request = Puppet::Indirector::Request.new(:file_content, :find, source_or_content.full_path.sub(/^\//,'')) connection = Puppet::Network::HttpPool.http_instance(source_or_content.server, source_or_content.port) connection.request_get(indirection2uri(request), add_accept_encoding({"Accept" => "raw"})) do |response| case response.code diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb index c74a1d47a..967e06aee 100755 --- a/lib/puppet/type/file/ensure.rb +++ b/lib/puppet/type/file/ensure.rb @@ -3,27 +3,27 @@ module Puppet require 'etc' desc "Whether to create files that don't currently exist. Possible values are *absent*, *present*, *file*, and *directory*. - Specifying ``present`` will match any form of file existence, and + Specifying `present` will match any form of file existence, and if the file is missing will create an empty file. Specifying - ``absent`` will delete the file (and directory if recurse => true). + `absent` will delete the file (and directory if recurse => true). Anything other than those values will be considered to be a symlink. - For instance, the following text creates a link:: + For instance, the following text creates a link: - # Useful on solaris - file { \"/etc/inetd.conf\": - ensure => \"/etc/inet/inetd.conf\" - } + # Useful on solaris + file { \"/etc/inetd.conf\": + ensure => \"/etc/inet/inetd.conf\" + } - You can make relative links:: + You can make relative links: - # Useful on solaris - file { \"/etc/inetd.conf\": - ensure => \"inet/inetd.conf\" - } + # Useful on solaris + file { \"/etc/inetd.conf\": + ensure => \"inet/inetd.conf\" + } If you need to make a relative link to a file named the same - as one of the valid values, you must prefix it with ``./`` or + as one of the valid values, you must prefix it with `./` or something similar. You can also make recursive symlinks, which will create a diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb index 9abf56d26..1ce56c843 100755 --- a/lib/puppet/type/file/mode.rb +++ b/lib/puppet/type/file/mode.rb @@ -13,14 +13,14 @@ module Puppet entries in a directory, and search/traverse allows you to access (read/write/execute) those entries.) Because of this feature, you can recursively make a directory and all of the files in it - world-readable by setting e.g.:: + world-readable by setting e.g.: - file { '/some/dir': - mode => 644, - recurse => true, - } + file { '/some/dir': + mode => 644, + recurse => true, + } - In this case all of the files underneath ``/some/dir`` will have + In this case all of the files underneath `/some/dir` will have mode 644, and all of the directories will have mode 755." @event = :file_changed diff --git a/lib/puppet/type/file/selcontext.rb b/lib/puppet/type/file/selcontext.rb index edcfb83b2..a33c6a000 100644 --- a/lib/puppet/type/file/selcontext.rb +++ b/lib/puppet/type/file/selcontext.rb @@ -56,7 +56,7 @@ module Puppet Puppet::Type.type(:file).newproperty(:seluser, :parent => Puppet::SELFileContext) do desc "What the SELinux user component of the context of the file should be. - Any valid SELinux user component is accepted. For example ``user_u``. + Any valid SELinux user component is accepted. For example `user_u`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled." @@ -67,7 +67,7 @@ module Puppet Puppet::Type.type(:file).newproperty(:selrole, :parent => Puppet::SELFileContext) do desc "What the SELinux role component of the context of the file should be. - Any valid SELinux role component is accepted. For example ``role_r``. + Any valid SELinux role component is accepted. For example `role_r`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled." @@ -78,7 +78,7 @@ module Puppet Puppet::Type.type(:file).newproperty(:seltype, :parent => Puppet::SELFileContext) do desc "What the SELinux type component of the context of the file should be. - Any valid SELinux type component is accepted. For example ``tmp_t``. + Any valid SELinux type component is accepted. For example `tmp_t`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled." @@ -89,8 +89,8 @@ module Puppet Puppet::Type.type(:file).newproperty(:selrange, :parent => Puppet::SELFileContext) do desc "What the SELinux range component of the context of the file should be. - Any valid SELinux range component is accepted. For example ``s0`` or - ``SystemHigh``. If not specified it defaults to the value returned by + Any valid SELinux range component is accepted. For example `s0` or + `SystemHigh`. If not specified it defaults to the value returned by matchpathcon for the file, if any exists. Only valid on systems with SELinux support enabled and that have support for MCS (Multi-Category Security)." diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 2eaf4a33f..7d03de2b0 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -12,7 +12,7 @@ module Puppet include Puppet::Util::Diff attr_accessor :source, :local - desc "Copy a file over the current file. Uses ``checksum`` to + desc "Copy a file over the current file. Uses `checksum` to determine when a file should be copied. Valid values are either fully qualified paths to files, or URIs. Currently supported URI types are *puppet* and *file*. @@ -20,47 +20,47 @@ module Puppet This is one of the primary mechanisms for getting content into applications that Puppet does not directly support and is very useful for those configuration files that don't change much across - sytems. For instance:: + sytems. For instance: - class sendmail { - file { \"/etc/mail/sendmail.cf\": - source => \"puppet://server/modules/module_name/sendmail.cf\" + class sendmail { + file { \"/etc/mail/sendmail.cf\": + source => \"puppet://server/modules/module_name/sendmail.cf\" + } } - } - You can also leave out the server name, in which case ``puppet agent`` - will fill in the name of its configuration server and ``puppet apply`` + You can also leave out the server name, in which case `puppet agent` + will fill in the name of its configuration server and `puppet apply` will use the local filesystem. This makes it easy to use the same configuration in both local and centralized forms. - Currently, only the ``puppet`` scheme is supported for source + Currently, only the `puppet` scheme is supported for source URL's. Puppet will connect to the file server running on - ``server`` to retrieve the contents of the file. If the - ``server`` part is empty, the behavior of the command-line - interpreter (``puppet apply``) and the client demon (``puppet agent``) differs - slightly: ``apply`` will look such a file up on the module path - on the local host, whereas ``agent`` will connect to the + `server` to retrieve the contents of the file. If the + `server` part is empty, the behavior of the command-line + interpreter (`puppet apply`) and the client demon (`puppet agent`) differs + slightly: `apply` will look such a file up on the module path + on the local host, whereas `agent` will connect to the puppet server that it received the manifest from. - See the `FileServingConfiguration fileserver configuration documentation`:trac: for information on how to configure + See the [fileserver configuration documentation](http://projects.puppetlabs.com/projects/puppet/wiki/File_Serving_Configuration) for information on how to configure and use file services within Puppet. If you specify multiple file sources for a file, then the first source that exists will be used. This allows you to specify - what amount to search paths for files:: - - file { \"/path/to/my/file\": - source => [ - \"/modules/nfs/files/file.$host\", - \"/modules/nfs/files/file.$operatingsystem\", - \"/modules/nfs/files/file\" - ] - } + what amount to search paths for files: + + file { \"/path/to/my/file\": + source => [ + \"/modules/nfs/files/file.$host\", + \"/modules/nfs/files/file.$operatingsystem\", + \"/modules/nfs/files/file\" + ] + } This will use the first found file as the source. - You cannot currently copy links using this mechanism; set ``links`` - to ``follow`` if any remote sources are links. + You cannot currently copy links using this mechanism; set `links` + to `follow` if any remote sources are links. " validate do |sources| @@ -94,6 +94,16 @@ module Puppet metadata && metadata.checksum end + # Look up (if necessary) and return remote content. + cached_attr(:content) do + raise Puppet::DevError, "No source for content was stored with the metadata" unless metadata.source + + unless tmp = Puppet::FileServing::Content.find(metadata.source) + fail "Could not find any content at %s" % metadata.source + end + tmp.content + end + # Copy the values from the source to the resource. Yay. def copy_source_values devfail "Somehow got asked to copy source values without any metadata" unless metadata diff --git a/lib/puppet/type/filebucket.rb b/lib/puppet/type/filebucket.rb index 65ff88411..7fd2ef46b 100755 --- a/lib/puppet/type/filebucket.rb +++ b/lib/puppet/type/filebucket.rb @@ -16,13 +16,13 @@ module Puppet undo transactions. You will normally want to define a single filebucket for your - whole network and then use that as the default backup location:: + whole network and then use that as the default backup location: - # Define the bucket - filebucket { main: server => puppet } + # Define the bucket + filebucket { main: server => puppet } - # Specify it as the default target - File { backup => main } + # Specify it as the default target + File { backup => main } Puppetmaster servers create a filebucket by default, so this will work in a default configuration." @@ -92,4 +92,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb index 9f26d2243..cde1cfd65 100755 --- a/lib/puppet/type/group.rb +++ b/lib/puppet/type/group.rb @@ -89,7 +89,7 @@ module Puppet newparam(:allowdupe, :boolean => true) do desc "Whether to allow duplicate GIDs. This option does not work on - FreeBSD (contract to the ``pw`` man page)." + FreeBSD (contract to the `pw` man page)." newvalues(:true, :false) @@ -97,4 +97,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index 929542d7c..1af74d886 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -5,19 +5,17 @@ module Puppet newproperty(:ip) do desc "The host's IP address, IPv4 or IPv6." - validate do |value| - unless value =~ /((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})/ - raise Puppet::Error, "Invalid IP address" + validate do |value| + unless value =~ /^((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})$/ + raise Puppet::Error, "Invalid IP address" + end end - end end newproperty(:host_aliases) do - desc 'Any aliases the host might have. Multiple values must be - specified as an array. Note that this property is not the same as - the "alias" metaparam; use this property to add aliases to a host - on disk, and "alias" to aliases for use in your Puppet scripts.' + desc "Any aliases the host might have. Multiple values must be + specified as an array." def insync?(is) is == @should @@ -28,21 +26,6 @@ module Puppet currentvalue.join(" ") end - def retrieve - is = super - case is - when String - is = is.split(/\s*,\s*/) - when Symbol - is = [is] - when Array - # nothing - else - raise Puppet::DevError, "Invalid @is type #{is.class}" - end - is - end - # We actually want to return the whole array here, not just the first # value. def should @@ -63,9 +46,14 @@ module Puppet validate do |value| raise Puppet::Error, "Host aliases cannot include whitespace" if value =~ /\s/ + raise Puppet::Error, "Host alias cannot be an empty string. Use an empty array to delete all host_aliases " if value =~ /^\s*$/ end end + newproperty(:comment) do + desc "A comment that will be attached to the line with a # character" + end + newproperty(:target) do desc "The file in which to store service information. Only used by those providers that write to disk." @@ -94,8 +82,7 @@ module Puppet end @doc = "Installs and manages host entries. For most systems, these - entries will just be in ``/etc/hosts``, but some systems (notably OS X) + entries will just be in `/etc/hosts`, but some systems (notably OS X) will have different solutions." end end - diff --git a/lib/puppet/type/k5login.rb b/lib/puppet/type/k5login.rb index 850e37733..a343e9e5c 100644 --- a/lib/puppet/type/k5login.rb +++ b/lib/puppet/type/k5login.rb @@ -3,15 +3,15 @@ # Plug-in type for handling k5login files Puppet::Type.newtype(:k5login) do - @doc = "Manage the .k5login file for a user. Specify the full path to - the .k5login file as the name and an array of principals as the + @doc = "Manage the `.k5login` file for a user. Specify the full path to + the `.k5login` file as the name and an array of principals as the property principals." ensurable # Principals that should exist in the file newproperty(:principals, :array_matching => :all) do - desc "The principals present in the .k5login file." + desc "The principals present in the `.k5login` file." end # The path/name of the k5login file diff --git a/lib/puppet/type/macauthorization.rb b/lib/puppet/type/macauthorization.rb index 9b17c279d..ef6fbb6c1 100644 --- a/lib/puppet/type/macauthorization.rb +++ b/lib/puppet/type/macauthorization.rb @@ -1,8 +1,7 @@ Puppet::Type.newtype(:macauthorization) do @doc = "Manage the Mac OS X authorization database. - See: - http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html for more information." + See the [Apple developer site](http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html) for more information." ensurable diff --git a/lib/puppet/type/mailalias.rb b/lib/puppet/type/mailalias.rb index 5534fdf25..ce7ca790b 100755 --- a/lib/puppet/type/mailalias.rb +++ b/lib/puppet/type/mailalias.rb @@ -46,4 +46,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/maillist.rb b/lib/puppet/type/maillist.rb index 7ac0e4e4f..732fbf09f 100755 --- a/lib/puppet/type/maillist.rb +++ b/lib/puppet/type/maillist.rb @@ -60,4 +60,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/mcx.rb b/lib/puppet/type/mcx.rb index e56b11938..4f0a6c3c5 100644 --- a/lib/puppet/type/mcx.rb +++ b/lib/puppet/type/mcx.rb @@ -21,8 +21,6 @@ Puppet::Type.newtype(:mcx) do @doc = "MCX object management using DirectoryService on OS X. -Original Author: Jeff McCune <mccune.jeff@gmail.com> - The default provider of this type merely manages the XML plist as reported by the dscl -mcxexport command. This is similar to the content property of the file type in Puppet. @@ -51,13 +49,13 @@ to other machines. newparam(:name) do desc "The name of the resource being managed. - The default naming convention follows Directory Service paths:: + The default naming convention follows Directory Service paths: - /Computers/localhost - /Groups/admin - /Users/localadmin + /Computers/localhost + /Groups/admin + /Users/localadmin - The ds_type and ds_name type parameters are not necessary if the + The `ds_type` and `ds_name` type parameters are not necessary if the default naming convention is followed." isnamevar end @@ -80,8 +78,10 @@ to other machines. newproperty(:content, :required_features => :manages_content) do desc "The XML Plist. The value of MCXSettings in DirectoryService. This is the standard output from the system command: - dscl localhost -mcxexport /Local/Default/<ds_type>/ds_name - Note that ds_type is capitalized and plural in the dscl command." + + dscl localhost -mcxexport /Local/Default/<ds_type>/ds_name + + Note that `ds_type` is capitalized and plural in the dscl command." end # JJM Yes, this is not DRY at all. Because of the code blocks diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb index 6ee5dd174..e8c6b3290 100755 --- a/lib/puppet/type/mount.rb +++ b/lib/puppet/type/mount.rb @@ -5,8 +5,8 @@ module Puppet information into the mount table. The actual behavior depends on the value of the 'ensure' parameter. - Note that if a ``mount`` receives an event from another resource, - it will try to remount the filesystems if ``ensure`` is set to ``mounted``." + Note that if a `mount` receives an event from another resource, + it will try to remount the filesystems if `ensure` is set to `mounted`." feature :refreshable, "The provider can remount the filesystem.", :methods => [:remount] @@ -15,10 +15,10 @@ module Puppet # call code when sync is called. newproperty(:ensure) do desc "Control what to do with this mount. Set this attribute to - ``umounted`` to make sure the filesystem is in the filesystem table - but not mounted (if the filesystem is currently mounted, it will be unmounted). Set it to ``absent`` to unmount (if necessary) and remove - the filesystem from the fstab. Set to ``mounted`` to add it to the - fstab and mount it. Set to ``present`` to add to fstab but not change + `umounted` to make sure the filesystem is in the filesystem table + but not mounted (if the filesystem is currently mounted, it will be unmounted). Set it to `absent` to unmount (if necessary) and remove + the filesystem from the fstab. Set to `mounted` to add it to the + fstab and mount it. Set to `present` to add to fstab but not change mount/unmount status" newvalue(:defined) do @@ -149,7 +149,7 @@ module Puppet newproperty(:dump) do desc "Whether to dump the mount. Not all platform support this. - Valid values are ``1`` or ``0``. or ``2`` on FreeBSD, Default is ``0``." + Valid values are `1` or `0`. or `2` on FreeBSD, Default is `0`." if Facter["operatingsystem"].value == "FreeBSD" newvalue(%r{(0|1|2)}) @@ -183,7 +183,7 @@ module Puppet end newparam(:path) do - desc "The deprecated name for the mount point. Please use ``name`` now." + desc "The deprecated name for the mount point. Please use `name` now." def value=(value) warning "'path' is deprecated for mounts. Please use 'name'." @@ -193,7 +193,7 @@ module Puppet end newparam(:remounts) do - desc "Whether the mount can be remounted ``mount -o remount``. If + desc "Whether the mount can be remounted `mount -o remount`. If this is false, then the filesystem will be unmounted and remounted manually, which is prone to failure." @@ -210,7 +210,7 @@ module Puppet def refresh # Only remount if we're supposed to be mounted. - provider.remount if self.should(:fstype) != "swap" and provider.mounted? + provider.remount if self.should(:fstype) != "swap" and self.should(:ensure) == :mounted end def value(name) @@ -222,4 +222,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/notify.rb b/lib/puppet/type/notify.rb index 97935e270..a6ec1dc8b 100644 --- a/lib/puppet/type/notify.rb +++ b/lib/puppet/type/notify.rb @@ -42,4 +42,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index f25464db5..51a866332 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -8,12 +8,12 @@ module Puppet @doc = "Manage packages. There is a basic dichotomy in package support right now: Some package types (e.g., yum and apt) can retrieve their own package files, while others (e.g., rpm and sun) cannot. For those package formats that cannot retrieve - their own files, you can use the ``source`` parameter to point to + their own files, you can use the `source` parameter to point to the correct file. Puppet will automatically guess the packaging format that you are using based on the platform you are on, but you can override it - using the ``provider`` parameter; each provider defines what it + using the `provider` parameter; each provider defines what it requires in order to function, and you must meet those requirements to use a given provider." @@ -22,7 +22,7 @@ module Puppet feature :uninstallable, "The provider can uninstall packages.", :methods => [:uninstall] feature :upgradeable, "The provider can upgrade to the latest version of a - package. This feature is used by specifying ``latest`` as the + package. This feature is used by specifying `latest` as the desired value for the package.", :methods => [:update, :latest] feature :purgeable, "The provider can purge packages. This generally means @@ -104,7 +104,6 @@ module Puppet end end - defaultto :installed # Override the parent method, because we've got all kinds of @@ -181,35 +180,35 @@ module Puppet system uses internally, which is sometimes (especially on Solaris) a name that is basically useless to humans. If you want to abstract package installation, then you can use aliases to provide - a common name to packages:: - - # In the 'openssl' class - $ssl = $operatingsystem ? { - solaris => SMCossl, - default => openssl - } - - # It is not an error to set an alias to the same value as the - # object name. - package { $ssl: - ensure => installed, - alias => openssl - } - - . etc. . - - $ssh = $operatingsystem ? { - solaris => SMCossh, - default => openssh - } - - # Use the alias to specify a dependency, rather than - # having another selector to figure it out again. - package { $ssh: - ensure => installed, - alias => openssh, - require => Package[openssl] - } + a common name to packages: + + # In the 'openssl' class + $ssl = $operatingsystem ? { + solaris => SMCossl, + default => openssl + } + + # It is not an error to set an alias to the same value as the + # object name. + package { $ssl: + ensure => installed, + alias => openssl + } + + . etc. . + + $ssh = $operatingsystem ? { + solaris => SMCossh, + default => openssh + } + + # Use the alias to specify a dependency, rather than + # having another selector to figure it out again. + package { $ssh: + ensure => installed, + alias => openssh, + require => Package[openssl] + } " isnamevar @@ -228,7 +227,7 @@ module Puppet end newparam(:type) do - desc "Deprecated form of ``provider``." + desc "Deprecated form of `provider`." munge do |value| warning "'type' is deprecated; use 'provider' instead" @@ -243,7 +242,7 @@ module Puppet This is currently only used on Solaris. The value will be validated according to system rules, which in the case of Solaris means that it should either be a fully qualified path - or it should be in /var/sadm/install/admin." + or it should be in `/var/sadm/install/admin`." end newparam(:responsefile) do @@ -320,4 +319,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/resources.rb b/lib/puppet/type/resources.rb index 34382e067..ae41b883b 100644 --- a/lib/puppet/type/resources.rb +++ b/lib/puppet/type/resources.rb @@ -1,12 +1,9 @@ -# Created by Luke Kanies on 2006-12-12. -# Copyright (c) 2006. All rights reserved. - require 'puppet' Puppet::Type.newtype(:resources) do @doc = "This is a metatype that can manage other resource types. Any metaparams specified here will be passed on to any generated resources, - so you can purge umanaged resources but set ``noop`` to true so the + so you can purge umanaged resources but set `noop` to true so the purging is only logged and does not actually happen." @@ -132,4 +129,3 @@ Puppet::Type.newtype(:resources) do %w{root nobody bin noaccess daemon sys} end end - diff --git a/lib/puppet/type/schedule.rb b/lib/puppet/type/schedule.rb index bedf1e536..82f17e533 100755 --- a/lib/puppet/type/schedule.rb +++ b/lib/puppet/type/schedule.rb @@ -16,7 +16,7 @@ module Puppet Thus, it behooves you to use wider scheduling (e.g., over a couple of hours) combined with periods and repetitions. For instance, if you wanted to restrict certain resources to only running once, between - the hours of two and 4 AM, then you would use this schedule:: + the hours of two and 4 AM, then you would use this schedule: schedule { maint: range => \"2 - 4\", @@ -33,7 +33,7 @@ module Puppet Puppet automatically creates a schedule for each valid period with the same name as that period (e.g., hourly and daily). Additionally, a schedule named *puppet* is created and used as the default, - with the following attributes:: + with the following attributes: schedule { puppet: period => hourly, @@ -45,11 +45,11 @@ module Puppet newparam(:name) do desc "The name of the schedule. This name is used to retrieve the - schedule when assigning it to an object:: + schedule when assigning it to an object: schedule { daily: period => daily, - range => [2, 4] + range => \"2 - 4\", } exec { \"/usr/bin/apt-get update\": @@ -65,7 +65,7 @@ module Puppet is always a range within a 24 hour period, and hours must be specified in numbers between 0 and 23, inclusive. Minutes and seconds can be provided, using the normal colon as a separator. - For instance:: + For instance: schedule { maintenance: range => \"1:30 - 4:30\" @@ -196,17 +196,17 @@ module Puppet Note that the period defines how often a given resource will get applied but not when; if you would like to restrict the hours that a given resource can be applied (e.g., only at night during - a maintenance window) then use the ``range`` attribute. + a maintenance window) then use the `range` attribute. If the provided periods are not sufficient, you can provide a value to the *repeat* attribute, which will cause Puppet to schedule the affected resources evenly in the period the - specified number of times. Take this schedule:: + specified number of times. Take this schedule: - schedule { veryoften: - period => hourly, - repeat => 6 - } + schedule { veryoften: + period => hourly, + repeat => 6 + } This can cause Puppet to apply that resource up to every 10 minutes. @@ -215,7 +215,7 @@ module Puppet internal factors might prevent it from actually running that often (e.g., long-running Puppet runs will squash conflictingly scheduled runs). - See the ``periodmatch`` attribute for tuning whether to match + See the `periodmatch` attribute for tuning whether to match times by their distance apart or by their specific value." newvalues(:hourly, :daily, :weekly, :monthly, :never) @@ -307,10 +307,10 @@ module Puppet Puppet.debug "Creating default schedules" result << self.new( - + :name => "puppet", :period => :hourly, - + :repeat => "2" ) @@ -318,9 +318,7 @@ module Puppet @parameters.find { |p| p.name == :period }.value_collection.values.each { |value| result << self.new( - :name => value.to_s, - :period => value ) } @@ -349,4 +347,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/selboolean.rb b/lib/puppet/type/selboolean.rb index cf873e987..204b89056 100644 --- a/lib/puppet/type/selboolean.rb +++ b/lib/puppet/type/selboolean.rb @@ -1,11 +1,7 @@ -# -# Simple module for manageing SELinux booleans -# - module Puppet newtype(:selboolean) do @doc = "Manages SELinux booleans on systems with SELinux support. The supported booleans - are any of the ones found in /selinux/booleans/." + are any of the ones found in `/selinux/booleans/`." newparam(:name) do desc "The name of the SELinux boolean to be managed." @@ -20,7 +16,7 @@ module Puppet newparam(:persistent) do desc "If set true, SELinux booleans will be written to disk and persist accross reboots. - The default is ``false``." + The default is `false`." defaultto :false newvalues(:true, :false) @@ -28,4 +24,3 @@ module Puppet end end - diff --git a/lib/puppet/type/selmodule.rb b/lib/puppet/type/selmodule.rb index 240d6e6d1..60be8a855 100644 --- a/lib/puppet/type/selmodule.rb +++ b/lib/puppet/type/selmodule.rb @@ -18,7 +18,7 @@ Puppet::Type.newtype(:selmodule) do newparam(:selmoduledir) do desc "The directory to look for the compiled pp module file in. - Currently defaults to /usr/share/selinux/targeted. If selmodulepath + Currently defaults to `/usr/share/selinux/targeted`. If selmodulepath is not specified the module will be looked for in this directory in a in a file called NAME.pp, where NAME is the value of the name parameter." @@ -34,9 +34,9 @@ Puppet::Type.newtype(:selmodule) do newproperty(:syncversion) do - desc "If set to ``true``, the policy will be reloaded if the + desc "If set to `true`, the policy will be reloaded if the version found in the on-disk file differs from the loaded - version. If set to ``false`` (the default) the the only check + version. If set to `false` (the default) the the only check that will be made is if the policy is loaded at all or not." newvalue(:true) @@ -51,4 +51,3 @@ Puppet::Type.newtype(:selmodule) do end end end - diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 8f5c6ee37..786a50448 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -17,10 +17,10 @@ module Puppet can provide the better behaviour you will get. Or, you can just use a platform that has very good service support. - Note that if a ``service`` receives an event from another resource, + Note that if a `service` receives an event from another resource, the service will get restarted. The actual command to restart the service depends on the platform. You can provide a special command - for restarting with the ``restart`` attribute." + for restarting with the `restart` attribute." feature :refreshable, "The provider can restart the service.", :methods => [:restart] @@ -83,7 +83,7 @@ module Puppet newparam(:binary) do desc "The path to the daemon. This is only used for systems that do not support init scripts. This binary will be - used to start the service if no ``start`` parameter is + used to start the service if no `start` parameter is provided." end @@ -94,12 +94,14 @@ module Puppet not support any kind of status command; thus, you must specify manually whether the service you are running has such a command (or you can specify a specific command using the - ``status`` parameter). + `status` parameter). If you do not specify anything, then the service name will be looked for in the process table." newvalues(:true, :false) + + defaultto :true end newparam(:name) do desc "The name of the service to run. This name is used to find @@ -140,7 +142,7 @@ module Puppet end newparam(:start) do desc "Specify a *start* command manually. Most service subsystems - support a ``start`` command, so this will not need to be + support a `start` command, so this will not need to be specified." end newparam(:status) do @@ -156,14 +158,14 @@ module Puppet newparam(:control) do desc "The control variable used to manage services (originally for HP-UX). - Defaults to the upcased service name plus ``START`` replacing dots with - underscores, for those providers that support the ``controllable`` feature." + Defaults to the upcased service name plus `START` replacing dots with + underscores, for those providers that support the `controllable` feature." defaultto { resource.name.gsub(".","_").upcase + "_START" if resource.provider.controllable? } end newparam :hasrestart do - desc "Specify that an init script has a ``restart`` option. Otherwise, - the init script's ``stop`` and ``start`` methods are used." + desc "Specify that an init script has a `restart` option. Otherwise, + the init script's `stop` and `start` methods are used." newvalues(:true, :false) end diff --git a/lib/puppet/type/ssh_authorized_key.rb b/lib/puppet/type/ssh_authorized_key.rb index 2bfa87b0f..e3320140e 100644 --- a/lib/puppet/type/ssh_authorized_key.rb +++ b/lib/puppet/type/ssh_authorized_key.rb @@ -34,8 +34,8 @@ module Puppet newproperty(:target) do desc "The absolute filename in which to store the SSH key. This property is optional and should only be used in cases where keys - are stored in a non-standard location (ie not in - ~user/.ssh/authorized_keys)." + are stored in a non-standard location (i.e.` not in + `~user/.ssh/authorized_keys`)." defaultto :absent @@ -96,4 +96,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb index e1adc7173..b7a1b8a8d 100755 --- a/lib/puppet/type/sshkey.rb +++ b/lib/puppet/type/sshkey.rb @@ -1,8 +1,8 @@ module Puppet newtype(:sshkey) do @doc = "Installs and manages ssh host keys. At this point, this type - only knows how to install keys into /etc/ssh/ssh_known_hosts, and - it cannot manage user authorized keys yet." + only knows how to install keys into `/etc/ssh/ssh_known_hosts`. See + the `ssh_authorized_key` type to manage authorized keys." ensurable @@ -23,9 +23,7 @@ module Puppet # to see if we can automatically glean any aliases. newproperty(:host_aliases) do desc 'Any aliases the host might have. Multiple values must be - specified as an array. Note that this property is not the same as - the "alias" metaparam; use this property to add aliases to a host - on disk, and "alias" to aliases for use in your Puppet scripts.' + specified as an array.' attr_accessor :meta @@ -56,7 +54,7 @@ module Puppet newproperty(:target) do desc "The file in which to store the ssh key. Only used by - the ``parsed`` provider." + the `parsed` provider." defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile) @resource.class.defaultprovider.default_target @@ -67,4 +65,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/stage.rb b/lib/puppet/type/stage.rb index d22cd7b70..0736dc4b9 100644 --- a/lib/puppet/type/stage.rb +++ b/lib/puppet/type/stage.rb @@ -1,11 +1,12 @@ Puppet::Type.newtype(:stage) do desc "A resource type for specifying run stages. The actual stage should - be specified on resources:: - class { foo: stage => pre } + be specified on resources: + + class { foo: stage => pre } - And you must manually control stage order:: + And you must manually control stage order: - stage { pre: before => Stage[main] } + stage { pre: before => Stage[main] } You automatically get a 'main' stage created, and by default all resources get inserted into that stage. diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb index a6605211e..93a7e96cf 100755 --- a/lib/puppet/type/tidy.rb +++ b/lib/puppet/type/tidy.rb @@ -1,11 +1,12 @@ Puppet::Type.newtype(:tidy) do require 'puppet/file_serving/fileset' + require 'puppet/file_bucket/dipper' @doc = "Remove unwanted files based on specific criteria. Multiple criteria are OR'd together, so a file that is too large but is not old enough will still get tidied. - If you don't specify either 'age' or 'size', then all files will + If you don't specify either `age` or `size`, then all files will be removed. This resource type works by generating a file resource for every file @@ -47,7 +48,7 @@ Puppet::Type.newtype(:tidy) do at least one of the patterns specified. Multiple patterns can be specified using an array. - Example:: + Example: tidy { \"/tmp\": age => \"1w\", @@ -55,7 +56,7 @@ Puppet::Type.newtype(:tidy) do matches => [ \"[0-9]pub*.tmp\", \"*.temp\", \"tmpfile?\" ] } - This removes files from \/tmp if they are one week old or older, + This removes files from `/tmp` if they are one week old or older, are not in a subdirectory and match one of the shell globs given. Note that the patterns are matched against the basename of each @@ -140,15 +141,17 @@ Puppet::Type.newtype(:tidy) do newparam(:size) do desc "Tidy files whose size is equal to or greater than the specified size. Unqualified values are in kilobytes, but - *b*, *k*, and *m* can be appended to specify *bytes*, *kilobytes*, - and *megabytes*, respectively. Only the first character is - significant, so the full word can also be used." + *b*, *k*, *m*, *g*, and *t* can be appended to specify *bytes*, + *kilobytes*, *megabytes*, *gigabytes*, and *terabytes*, respectively. + Only the first character is significant, so the full word can also + be used." @@sizeconvertors = { :b => 0, :k => 1, :m => 2, - :g => 3 + :g => 3, + :t => 4 } def convert(unit, multi) diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index c7ac796a3..c8110bb69 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -12,7 +12,7 @@ module Puppet This resource type uses the prescribed native tools for creating groups and generally uses POSIX APIs for retrieving information - about them. It does not directly modify /etc/passwd or anything." + about them. It does not directly modify `/etc/passwd` or anything." feature :allows_duplicates, "The provider supports duplicate users with the same UID." @@ -24,9 +24,16 @@ module Puppet "The provider can modify user passwords, by accepting a password hash." + feature :manages_password_age, + "The provider can set age requirements and restrictions for + passwords." + feature :manages_solaris_rbac, "The provider can manage roles and normal users" + feature :manages_expiry, + "The provider can manage the expiry date for a user." + newproperty(:ensure, :parent => Puppet::Property::Ensure) do newvalue(:present, :event => :user_created) do provider.create @@ -157,6 +164,43 @@ module Puppet end end + newproperty(:password_min_age, :required_features => :manages_password_age) do + desc "The minimum amount of time in days a password must be used before it may be changed" + + munge do |value| + case value + when String + Integer(value) + else + value + end + end + + validate do |value| + if value.to_s !~ /^\d+$/ + raise ArgumentError, "Password minimum age must be provided as a number" + end + end + end + + newproperty(:password_max_age, :required_features => :manages_password_age) do + desc "The maximum amount of time in days a password may be used before it must be changed" + + munge do |value| + case value + when String + Integer(value) + else + value + end + end + + validate do |value| + if value.to_s !~ /^\d+$/ + raise ArgumentError, "Password maximum age must be provided as a number" + end + end + end newproperty(:groups, :parent => Puppet::Property::List) do desc "The groups of which the user is a member. The primary @@ -210,6 +254,17 @@ module Puppet end end + newproperty(:expiry, :required_features => :manages_expiry) do + desc "The expiry date for this user. Must be provided in + a zero padded YYYY-MM-DD format - e.g 2010-02-19." + + validate do |value| + if value !~ /^\d{4}-\d{2}-\d{2}$/ + raise ArgumentError, "Expiry dates must be YYYY-MM-DD" + end + end + end + # Autorequire the group, if it's around autorequire(:group) do autos = [] @@ -381,4 +436,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/whit.rb b/lib/puppet/type/whit.rb new file mode 100644 index 000000000..55bfcfb46 --- /dev/null +++ b/lib/puppet/type/whit.rb @@ -0,0 +1,11 @@ +Puppet::Type.newtype(:whit) do + desc "The smallest possible resource type, for when you need a resource and naught else." + + newparam :name do + desc "The name of the whit, because it must have one." + end + + def to_s + "Class[#{name}]" + end +end diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb index e0ed3ad37..160b2164d 100644 --- a/lib/puppet/type/yumrepo.rb +++ b/lib/puppet/type/yumrepo.rb @@ -52,8 +52,9 @@ module Puppet newtype(:yumrepo) do @doc = "The client-side description of a yum repository. Repository - configurations are found by parsing /etc/yum.conf and - the files indicated by reposdir in that file (see yum.conf(5) for details) + configurations are found by parsing `/etc/yum.conf` and + the files indicated by the `reposdir` option in that file + (see yum.conf(5) for details) Most parameters are identical to the ones documented in yum.conf(5) @@ -85,7 +86,7 @@ module Puppet clear inifile.each_section do |s| next if s.name == "main" - obj = create(:name => s.name, :audit => check) + obj = new(:name => s.name, :audit => check) current_values = obj.retrieve obj.eachproperty do |property| if current_values[property].nil? @@ -294,6 +295,12 @@ module Puppet newvalue(%r{(0|1)}) { } end + newproperty(:http_caching, :parent => Puppet::IniProperty) do + desc "Either 'packages' or 'all' or 'none'.\n#{ABSENT_DOC}" + newvalue(:absent) { self.should = :absent } + newvalue(%r(packages|all|none)) { } + end + newproperty(:timeout, :parent => Puppet::IniProperty) do desc "Number of seconds to wait for a connection before timing out.\n#{ABSENT_DOC}" @@ -324,6 +331,12 @@ module Puppet newvalue(%r{[1-9][0-9]?}) { } end + newproperty(:cost, :parent => Puppet::IniProperty) do + desc "Cost of this repository.\n#{ABSENT_DOC}" + newvalue(:absent) { self.should = :absent } + newvalue(%r{\d+}) { } + end + newproperty(:proxy, :parent => Puppet::IniProperty) do desc "URL to the proxy server for this repository.\n#{ABSENT_DOC}" newvalue(:absent) { self.should = :absent } diff --git a/lib/puppet/type/zfs.rb b/lib/puppet/type/zfs.rb index e1a972ddf..1757931f8 100755 --- a/lib/puppet/type/zfs.rb +++ b/lib/puppet/type/zfs.rb @@ -33,7 +33,7 @@ module Puppet end newproperty(:snapdir) do - desc "The sharenfs property." + desc "The snapdir property." end autorequire(:zpool) do @@ -48,4 +48,3 @@ module Puppet end end end - diff --git a/lib/puppet/type/zone.rb b/lib/puppet/type/zone.rb index d523c469a..408d6f5dd 100644 --- a/lib/puppet/type/zone.rb +++ b/lib/puppet/type/zone.rb @@ -69,9 +69,9 @@ Puppet::Type.newtype(:zone) do ensurable do desc "The running state of the zone. The valid states directly reflect - the states that ``zoneadm`` provides. The states are linear, - in that a zone must be ``configured`` then ``installed``, and - only then can be ``running``. Note also that ``halt`` is currently + the states that `zoneadm` provides. The states are linear, + in that a zone must be `configured` then `installed`, and + only then can be `running`. Note also that `halt` is currently used to stop zones." @states = {} @@ -313,31 +313,31 @@ Puppet::Type.newtype(:zone) do # only used to boot the zone the very first time. newparam(:sysidcfg) do desc %{The text to go into the sysidcfg file when the zone is first - booted. The best way is to use a template:: - - # $templatedir/sysidcfg - system_locale=en_US - timezone=GMT - terminal=xterms - security_policy=NONE - root_password=<%= password %> - timeserver=localhost - name_service=DNS {domain_name=<%= domain %> name_server=<%= nameserver %>} - network_interface=primary {hostname=<%= realhostname %> - ip_address=<%= ip %> - netmask=<%= netmask %> - protocol_ipv6=no - default_route=<%= defaultroute %>} - nfs4_domain=dynamic - - And then call that:: - - zone { myzone: - ip => "bge0:192.168.0.23", - sysidcfg => template(sysidcfg), - path => "/opt/zones/myzone", - realhostname => "fully.qualified.domain.name" - } + booted. The best way is to use a template: + + # $templatedir/sysidcfg + system_locale=en_US + timezone=GMT + terminal=xterms + security_policy=NONE + root_password=<%= password %> + timeserver=localhost + name_service=DNS {domain_name=<%= domain %> name_server=<%= nameserver %>} + network_interface=primary {hostname=<%= realhostname %> + ip_address=<%= ip %> + netmask=<%= netmask %> + protocol_ipv6=no + default_route=<%= defaultroute %>} + nfs4_domain=dynamic + + And then call that: + + zone { myzone: + ip => "bge0:192.168.0.23", + sysidcfg => template(sysidcfg), + path => "/opt/zones/myzone", + realhostname => "fully.qualified.domain.name" + } The sysidcfg only matters on the first booting of the zone, so Puppet only checks for it at that time.} diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb index 80e635504..49cce552a 100755 --- a/lib/puppet/type/zpool.rb +++ b/lib/puppet/type/zpool.rb @@ -44,8 +44,11 @@ module Puppet end newproperty(:mirror, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do - desc "List of all the devices to mirror for this pool. Each mirror should be a space separated string. - mirror => [\"disk1 disk2\", \"disk3 disk4\"]" + desc "List of all the devices to mirror for this pool. Each mirror should be a space separated string: + + mirror => [\"disk1 disk2\", \"disk3 disk4\"] + + " validate do |value| raise ArgumentError, "mirror names must be provided as string separated, not a comma-separated list" if value.include?(",") @@ -53,8 +56,11 @@ module Puppet end newproperty(:raidz, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do - desc "List of all the devices to raid for this pool. Should be an array of space separated strings. - raidz => [\"disk1 disk2\", \"disk3 disk4\"]" + desc "List of all the devices to raid for this pool. Should be an array of space separated strings: + + raidz => [\"disk1 disk2\", \"disk3 disk4\"] + + " validate do |value| raise ArgumentError, "raid names must be provided as string separated, not a comma-separated list" if value.include?(",") @@ -84,4 +90,3 @@ module Puppet end end end - diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index bb4127089..850d147e2 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -3,6 +3,7 @@ require 'puppet/util/monkey_patches' require 'sync' require 'puppet/external/lock' +require 'monitor' module Puppet # A command failed to execute. @@ -17,13 +18,29 @@ module Util require 'puppet/util/posix' extend Puppet::Util::POSIX - # Create a hash to store the different sync objects. - @@syncresources = {} + @@sync_objects = {}.extend MonitorMixin - # Return the sync object associated with a given resource. - def self.sync(resource) - @@syncresources[resource] ||= Sync.new - @@syncresources[resource] + def self.activerecord_version + if (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR)) + ([::ActiveRecord::VERSION::MAJOR, ::ActiveRecord::VERSION::MINOR].join('.').to_f) + else + 0 + end + end + + + def self.synchronize_on(x,type) + sync_object,users = 0,1 + begin + @@sync_objects.synchronize { + (@@sync_objects[x] ||= [Sync.new,0])[users] += 1 + } + @@sync_objects[x][sync_object].synchronize(type) { yield } + ensure + @@sync_objects.synchronize { + @@sync_objects.delete(x) unless (@@sync_objects[x][users] -= 1) > 0 + } + end end # Change the process to a different user @@ -181,7 +198,7 @@ module Util end end - def binary(bin) + def which(bin) if bin =~ /^\// return bin if FileTest.file? bin and FileTest.executable? bin else @@ -192,7 +209,7 @@ module Util end nil end - module_function :binary + module_function :which # Execute the provided command in a pipe, yielding the pipe object. def execpipe(command, failonfail = true) @@ -351,9 +368,7 @@ module Util # Create an exclusive lock. def threadlock(resource, type = Sync::EX) - Puppet::Util.sync(resource).synchronize(type) do - yield - end + Puppet::Util.synchronize_on(resource,type) { yield } end # Because some modules provide their own version of this method. @@ -363,15 +378,10 @@ module Util def memory unless defined?(@pmap) - pmap = %x{which pmap 2>/dev/null}.chomp - if $CHILD_STATUS != 0 or pmap =~ /^no/ - @pmap = nil - else - @pmap = pmap - end + @pmap = which('pmap') end if @pmap - return %x{pmap #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i + %x{#{@pmap} #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i else 0 end diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index c293ac14a..f0dd0a5c5 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -131,11 +131,23 @@ class Puppet::Util::Autoload # We have to require this late in the process because otherwise we might have # load order issues. require 'puppet/node/environment' - Puppet::Node::Environment.new(env).modulepath.collect do |dir| - Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f) } - end.flatten.collect { |d| [File.join(d, "plugins"), File.join(d, "lib")] }.flatten.find_all do |d| - FileTest.directory?(d) - end + + real_env = Puppet::Node::Environment.new(env) + + # We're using a per-thread cache of said module directories, so that + # we don't scan the filesystem each time we try to load something with + # this autoload instance. But since we don't want to cache for the eternity + # this env_module_directories gets reset after the compilation on the master. + # This is also reset after an agent ran. + # One of the side effect of this change is that this module directories list will be + # shared among all autoload that we have running at a time. But that won't be an issue + # as by definition those directories are shared by all autoload. + Thread.current[:env_module_directories] ||= {} + Thread.current[:env_module_directories][real_env] ||= real_env.modulepath.collect do |dir| + Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f) } + end.flatten.collect { |d| [File.join(d, "plugins"), File.join(d, "lib")] }.flatten.find_all do |d| + FileTest.directory?(d) + end end def search_directories(env=nil) diff --git a/lib/puppet/util/cacher.rb b/lib/puppet/util/cacher.rb index 8785c694f..3dddec0d4 100644 --- a/lib/puppet/util/cacher.rb +++ b/lib/puppet/util/cacher.rb @@ -1,3 +1,5 @@ +require 'monitor' + module Puppet::Util::Cacher module Expirer attr_reader :timestamp @@ -49,7 +51,7 @@ module Puppet::Util::Cacher define_method(name.to_s + "=") do |value| # Make sure the cache timestamp is set cache_timestamp - value_cache[name] = value + value_cache.synchronize { value_cache[name] = value } end if ttl = options[:ttl] @@ -70,6 +72,7 @@ module Puppet::Util::Cacher # Methods that get added to instances. module InstanceMethods + def expire # Only expire if we have an expirer. This is # mostly so that we can comfortably handle cases @@ -92,15 +95,17 @@ module Puppet::Util::Cacher end def cached_value(name) - # Allow a nil expirer, in which case we regenerate the value every time. - if expired_by_expirer?(name) - value_cache.clear - @cache_timestamp = Time.now - elsif expired_by_ttl?(name) - value_cache.delete(name) + value_cache.synchronize do + # Allow a nil expirer, in which case we regenerate the value every time. + if expired_by_expirer?(name) + value_cache.clear + @cache_timestamp = Time.now + elsif expired_by_ttl?(name) + value_cache.delete(name) + end + value_cache[name] = send("init_#{name}") unless value_cache.include?(name) + value_cache[name] end - value_cache[name] = send("init_#{name}") unless value_cache.include?(name) - value_cache[name] end def expired_by_expirer?(name) @@ -121,7 +126,7 @@ module Puppet::Util::Cacher end def value_cache - @value_cache ||= {} + @value_cache ||= {}.extend(MonitorMixin) end end end diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb index 2a97ee069..3562a3dc0 100644 --- a/lib/puppet/util/command_line.rb +++ b/lib/puppet/util/command_line.rb @@ -62,7 +62,7 @@ module Puppet external_command = "puppet-#{subcommand_name}" require 'puppet/util' - path_to_subcommand = Puppet::Util.binary( external_command ) + path_to_subcommand = Puppet::Util.which( external_command ) return false unless path_to_subcommand system( path_to_subcommand, *args ) diff --git a/lib/puppet/util/command_line/puppetdoc b/lib/puppet/util/command_line/puppetdoc index d9bbbec33..0fa1830d6 100755 --- a/lib/puppet/util/command_line/puppetdoc +++ b/lib/puppet/util/command_line/puppetdoc @@ -8,15 +8,15 @@ # # = Usage # -# puppet doc [-a|--all] [-h|--help] [-o|--outputdir <rdoc outputdir>] [-m|--mode <text|pdf|markdown|trac|rdoc>] +# puppet doc [-a|--all] [-h|--help] [-o|--outputdir <rdoc outputdir>] [-m|--mode <text|pdf|rdoc>] # [-r|--reference <[type]|configuration|..>] [--charset CHARSET] [manifest-file] # # = Description # -# If mode is not 'rdoc', then this command generates a restructured-text document describing all installed +# If mode is not 'rdoc', then this command generates a Markdown document describing all installed # Puppet types or all allowable arguments to puppet executables. It is largely # meant for internal use and is used to generate the reference document -# available on the Reductive Labs web site. +# available on the Puppet Labs web site. # # In 'rdoc' mode, this command generates an html RDoc hierarchy describing the manifests that # are in 'manifestdir' and 'modulepath' configuration directives. @@ -37,7 +37,7 @@ # Specifies the directory where to output the rdoc documentation in 'rdoc' mode. # # mode:: -# Determine the output mode. Valid modes are 'text', 'trac', 'pdf', 'markdown' and 'rdoc'. The 'pdf' and 'markdown' modes create PDF or Markdown formatted files in the /tmp directory. Note that 'trac' mode only works on Reductive Labs servers. The default mode is 'text'. In 'rdoc' mode you must provide 'manifests-path' +# Determine the output mode. Valid modes are 'text', 'trac', 'pdf' and 'rdoc'. The 'pdf' mode creates PDF formatted files in the /tmp directory. The default mode is 'text'. In 'rdoc' mode you must provide 'manifests-path' # # reference:: # Build a particular reference. Get a list of references by running +puppet doc --list+. @@ -53,7 +53,7 @@ # or # $ puppet doc /etc/puppet/manifests/site.pp # or -# $ puppet doc -m markdown -r configuration +# $ puppet doc -m pdf -r configuration # # = Author # diff --git a/lib/puppet/util/command_line/puppetrun b/lib/puppet/util/command_line/puppetrun index ee95c47eb..27cd775b9 100755 --- a/lib/puppet/util/command_line/puppetrun +++ b/lib/puppet/util/command_line/puppetrun @@ -54,8 +54,6 @@ # This is what you would install on your Puppet master; non-master hosts could # leave off the 'fileserver' and 'puppetmaster' namespaces. # -# Expect more documentation on this eventually. -# # = Options # # Note that any configuration parameter that's valid in the configuration file diff --git a/lib/puppet/util/command_line/ralsh b/lib/puppet/util/command_line/ralsh index 68ad92d84..83338fcbc 100755 --- a/lib/puppet/util/command_line/ralsh +++ b/lib/puppet/util/command_line/ralsh @@ -59,23 +59,23 @@ # types: # List all available types. # -# verbose:: +# verbose: # Print extra information. # # = Example # -# This example uses ``puppet resource`` to return Puppet configuration for the user ``luke``:: -# -# $ puppet resource user luke -# user { 'luke': -# home => '/home/luke', -# uid => '100', -# ensure => 'present', -# comment => 'Luke Kanies,,,', -# gid => '1000', -# shell => '/bin/bash', -# groups => ['sysadmin','audio','video','puppet'] -# } +# This example uses `puppet resource` to return Puppet configuration for the user `luke`: +# +# $ puppet resource user luke +# user { 'luke': +# home => '/home/luke', +# uid => '100', +# ensure => 'present', +# comment => 'Luke Kanies,,,', +# gid => '1000', +# shell => '/bin/bash', +# groups => ['sysadmin','audio','video','puppet'] +# } # # = Author # diff --git a/lib/puppet/util/docs.rb b/lib/puppet/util/docs.rb index efd054d85..4344d67ab 100644 --- a/lib/puppet/util/docs.rb +++ b/lib/puppet/util/docs.rb @@ -47,25 +47,19 @@ module Puppet::Util::Docs lengths[i] = value.to_s.length if value.to_s.length > lengths[i] end - # Add the top header row - str += lengths.collect { |num| "=" * num }.join(" ") + "\n" + # Add the header names + str += headers.zip(lengths).collect { |value, num| pad(value, num) }.join(" | ") + " |" + "\n" - # And the header names - str += headers.zip(lengths).collect { |value, num| pad(value, num) }.join(" ") + "\n" - - # And the second header row - str += lengths.collect { |num| "=" * num }.join(" ") + "\n" + # And the header row + str += lengths.collect { |num| "-" * num }.join(" | ") + " |" + "\n" # Now each data row data.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |name, rows| str += [name, rows].flatten.zip(lengths).collect do |value, length| pad(value, length) - end.join(" ") + "\n" + end.join(" | ") + " |" + "\n" end - # And the bottom line row - str += lengths.collect { |num| "=" * num }.join(" ") + "\n" - str + "\n" end @@ -111,4 +105,3 @@ module Puppet::Util::Docs module_function :scrub end - diff --git a/lib/puppet/util/file_locking.rb b/lib/puppet/util/file_locking.rb index 8b194ed83..18744cab7 100644 --- a/lib/puppet/util/file_locking.rb +++ b/lib/puppet/util/file_locking.rb @@ -6,7 +6,7 @@ module Puppet::Util::FileLocking # Create a shared lock for reading def readlock(file) raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file) - Puppet::Util.sync(file).synchronize(Sync::SH) do + Puppet::Util.synchronize_on(file,Sync::SH) do File.open(file) { |f| f.lock_shared { |lf| yield lf } } @@ -33,9 +33,12 @@ module Puppet::Util::FileLocking end end - Puppet::Util.sync(file).synchronize(Sync::EX) do - File.open(file, "w", mode) do |rf| + Puppet::Util.synchronize_on(file,Sync::EX) do + File.open(file, File::Constants::CREAT | File::Constants::WRONLY, mode) do |rf| rf.lock_exclusive do |lrf| + # poor's man open(2) O_EXLOCK|O_TRUNC + lrf.seek(0, IO::SEEK_SET) + lrf.truncate(0) yield lrf end end diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb index 36a765c61..a5aacc265 100644 --- a/lib/puppet/util/log.rb +++ b/lib/puppet/util/log.rb @@ -57,6 +57,7 @@ class Puppet::Util::Log destinations.keys.each { |dest| close(dest) } + raise Puppet::DevError.new("Log.close_all failed to close #{@destinations.keys.inspect}") if !@destinations.empty? end # Flush any log destinations that support such operations. diff --git a/lib/puppet/util/log/destinations.rb b/lib/puppet/util/log/destinations.rb index 22b3dedb2..2e2f9a5b7 100644 --- a/lib/puppet/util/log/destinations.rb +++ b/lib/puppet/util/log/destinations.rb @@ -203,8 +203,20 @@ Puppet::Util::Log.newdesttype :report do end # Log to an array, just for testing. +module Puppet::Test + class LogCollector + def initialize(logs) + @logs = logs + end + + def <<(value) + @logs << value + end + end +end + Puppet::Util::Log.newdesttype :array do - match "Array" + match "Puppet::Test::LogCollector" def initialize(messages) @messages = messages diff --git a/lib/puppet/util/metric.rb b/lib/puppet/util/metric.rb index 7e14a5fec..7fdc6951f 100644 --- a/lib/puppet/util/metric.rb +++ b/lib/puppet/util/metric.rb @@ -31,9 +31,12 @@ class Puppet::Util::Metric start ||= Time.now.to_i - 5 - @rrd = RRDtool.new(self.path) args = [] + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd = RRDtool.new(self.path) + end + values.each { |value| # the 7200 is the heartbeat -- this means that any data that isn't # more frequently than every two hours gets thrown away @@ -42,18 +45,26 @@ class Puppet::Util::Metric args.push "RRA:AVERAGE:0.5:1:300" begin - @rrd.create( Puppet[:rrdinterval].to_i, start, args) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd.create( Puppet[:rrdinterval].to_i, start, args) + else + RRD.create( self.path, '-s', Puppet[:rrdinterval].to_i.to_s, '-b', start.to_i.to_s, *args) + end rescue => detail raise "Could not create RRD file #{path}: #{detail}" end end def dump - puts @rrd.info + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + puts @rrd.info + else + puts RRD.info(self.path) + end end def graph(range = nil) - unless Puppet.features.rrd? + unless Puppet.features.rrd? || Puppet.features.rrd_legacy? Puppet.warning "RRD library is missing; cannot graph metrics" return end @@ -82,14 +93,26 @@ class Puppet::Util::Metric args << lines args.flatten! if range - args.push("--start",range[0],"--end",range[1]) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + args.push("--start",range[0],"--end",range[1]) + else + args.push("--start",range[0].to_i.to_s,"--end",range[1].to_i.to_s) + end else - args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i) + else + args.push("--start", (Time.now.to_i - time).to_s, "--end", Time.now.to_i.to_s) + end end begin #Puppet.warning "args = #{args}" - RRDtool.graph( args ) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + RRDtool.graph( args ) + else + RRD.graph( *args ) + end rescue => detail Puppet.err "Failed to graph #{self.name}: #{detail}" end @@ -99,7 +122,7 @@ class Puppet::Util::Metric def initialize(name,label = nil) @name = name.to_s - @label = label || labelize(name) + @label = label || self.class.labelize(name) @values = [] end @@ -109,18 +132,20 @@ class Puppet::Util::Metric end def newvalue(name,value,label = nil) - label ||= labelize(name) + label ||= self.class.labelize(name) @values.push [name,label,value] end def store(time) - unless Puppet.features.rrd? + unless Puppet.features.rrd? || Puppet.features.rrd_legacy? Puppet.warning "RRD library is missing; cannot store metrics" return end self.create(time - 5) unless FileTest.exists?(self.path) - @rrd ||= RRDtool.new(self.path) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd ||= RRDtool.new(self.path) + end # XXX this is not terribly error-resistant args = [time] @@ -133,7 +158,11 @@ class Puppet::Util::Metric arg = args.join(":") template = temps.join(":") begin - @rrd.update( template, [ arg ] ) + if Puppet.features.rrd_legacy? && ! Puppet.features.rrd? + @rrd.update( template, [ arg ] ) + else + RRD.update( self.path, '-t', template, arg ) + end #system("rrdtool updatev #{self.path} '#{arg}'") rescue => detail raise Puppet::Error, "Failed to update #{self.name}: #{detail}" @@ -144,10 +173,8 @@ class Puppet::Util::Metric @values.sort { |a, b| a[1] <=> b[1] } end - private - # Convert a name into a label. - def labelize(name) + def self.labelize(name) name.to_s.capitalize.gsub("_", " ") end end diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb index e035afd9f..1c35ae523 100644 --- a/lib/puppet/util/monkey_patches.rb +++ b/lib/puppet/util/monkey_patches.rb @@ -1,4 +1,7 @@ -Process.maxgroups = 1024 + +unless defined? JRUBY_VERSION + Process.maxgroups = 1024 +end module RDoc def self.caller(skip=nil) @@ -22,7 +25,7 @@ end [Object, Exception, Integer, Struct, Date, Time, Range, Regexp, Hash, Array, Float, String, FalseClass, TrueClass, Symbol, NilClass, Class].each { |cls| cls.class_eval do - def to_yaml + def to_yaml(ignored=nil) ZAML.dump(self) end end @@ -45,3 +48,26 @@ if RUBY_VERSION == '1.8.7' end end + +class Object + # ActiveSupport 2.3.x mixes in a dangerous method + # that can cause rspec to fork bomb + # and other strange things like that. + def daemonize + raise NotImplementedError, "Kernel.daemonize is too dangerous, please don't try to use it." + end +end + +# Workaround for yaml_initialize, which isn't supported before Ruby +# 1.8.3. +if RUBY_VERSION == '1.8.1' || RUBY_VERSION == '1.8.2' + YAML.add_ruby_type( /^object/ ) { |tag, val| + type, obj_class = YAML.read_type_class( tag, Object ) + r = YAML.object_maker( obj_class, val ) + if r.respond_to? :yaml_initialize + r.instance_eval { instance_variables.each { |name| remove_instance_variable name } } + r.yaml_initialize(tag, val) + end + r + } +end diff --git a/lib/puppet/util/nagios_maker.rb b/lib/puppet/util/nagios_maker.rb index 59ed820f9..863fe24fa 100644 --- a/lib/puppet/util/nagios_maker.rb +++ b/lib/puppet/util/nagios_maker.rb @@ -45,17 +45,16 @@ module Puppet::Util::NagiosMaker provider.nagios_type type.desc "The Nagios type #{name.to_s}. This resource type is autogenerated using the - model developed in Naginator_, and all of the Nagios types are generated using the + model developed in Naginator, and all of the Nagios types are generated using the same code and the same library. This type generates Nagios configuration statements in Nagios-parseable configuration - files. By default, the statements will be added to ``#{target}``, but - you can send them to a different file by setting their ``target`` attribute. + files. By default, the statements will be added to `#{target}`, but + you can send them to a different file by setting their `target` attribute. - You can purge Nagios resources using the ``resources`` type, but *only* + You can purge Nagios resources using the `resources` type, but *only* in the default file locations. This is an architectural limitation. - .. _naginator: http://projects.reductivelabs.com/projects/naginator " end end diff --git a/lib/puppet/util/provider_features.rb b/lib/puppet/util/provider_features.rb index ac294d20d..30e8dcb39 100644 --- a/lib/puppet/util/provider_features.rb +++ b/lib/puppet/util/provider_features.rb @@ -72,7 +72,7 @@ module Puppet::Util::ProviderFeatures names = @features.keys.sort { |a,b| a.to_s <=> b.to_s } names.each do |name| doc = @features[name].docs.gsub(/\n\s+/, " ") - str += "- **#{name}**: #{doc}\n" + str += "- *#{name}*: #{doc}\n" end if providers.length > 0 @@ -83,7 +83,7 @@ module Puppet::Util::ProviderFeatures prov = provider(provname) names.each do |name| if prov.feature?(name) - data[provname] << "**X**" + data[provname] << "*X*" else data[provname] << "" end diff --git a/lib/puppet/util/rdoc.rb b/lib/puppet/util/rdoc.rb index 4a80b069b..bdac579d6 100644 --- a/lib/puppet/util/rdoc.rb +++ b/lib/puppet/util/rdoc.rb @@ -10,24 +10,25 @@ module Puppet::Util::RDoc # then rdoc require 'rdoc/rdoc' + require 'rdoc/options' # load our parser require 'puppet/util/rdoc/parser' r = RDoc::RDoc.new - RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new( + RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new( "puppet/util/rdoc/generators/puppet_generator.rb", - "PuppetGenerator".intern, + "PuppetGenerator".intern, + "puppet") - "puppet") # specify our own format & where to output options = [ "--fmt", "puppet", "--quiet", - "--force-update", "--exclude", "/modules/[^/]*/files/.*\.pp$", "--op", outputdir ] + options << "--force-update" if Options::OptionList.options.any? { |o| o[0] == "--force-update" } options += [ "--charset", charset] if charset options += files @@ -41,7 +42,7 @@ module Puppet::Util::RDoc def manifestdoc(files) Puppet[:ignoreimport] = true files.select { |f| FileTest.file?(f) }.each do |f| - parser = Puppet::Parser::Parser.new(:environment => Puppet[:environment]) + parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new(Puppet[:environment])) parser.file = f ast = parser.parse output(f, ast) diff --git a/lib/puppet/util/rdoc/generators/puppet_generator.rb b/lib/puppet/util/rdoc/generators/puppet_generator.rb index 9caeacd5e..e6bbb2e1e 100644 --- a/lib/puppet/util/rdoc/generators/puppet_generator.rb +++ b/lib/puppet/util/rdoc/generators/puppet_generator.rb @@ -88,6 +88,12 @@ module Generators @modules = {} @allclasses = {} + # remove unknown toplevels + # it can happen that RDoc triggers a different parser for some files (ie .c, .cc or .h) + # in this case RDoc generates a RDoc::TopLevel which we do not support in this generator + # So let's make sure we don't generate html for those. + @toplevels = @toplevels.select { |tl| tl.is_a? RDoc::PuppetTopLevel } + # build the modules, classes and per modules classes and define list @toplevels.each do |toplevel| next unless toplevel.document_self diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb index 573d1766f..ce34442ab 100644 --- a/lib/puppet/util/rdoc/parser.rb +++ b/lib/puppet/util/rdoc/parser.rb @@ -15,7 +15,9 @@ module RDoc class Parser extend ParserFactory - attr_accessor :ast, :input_file_name, :top_level + SITE = "__site__" + + attr_accessor :input_file_name, :top_level # parser registration into RDoc parse_files_matching(/\.(rb|pp)$/) @@ -31,13 +33,19 @@ class Parser # main entry point def scan - Puppet.info "rdoc: scanning #{@input_file_name}" - if @input_file_name =~ /\.pp$/ - @parser = Puppet::Parser::Parser.new(Puppet[:environment]) - @parser.file = @input_file_name - @ast = @parser.parse + environment = Puppet::Node::Environment.new + unless environment.known_resource_types.watching_file?(@input_file_name) + Puppet.info "rdoc: scanning #{@input_file_name}" + if @input_file_name =~ /\.pp$/ + @parser = Puppet::Parser::Parser.new(environment) + @parser.file = @input_file_name + @known_resource_types = environment.known_resource_types + @parser.parse.instantiate('').each do |type| + @known_resource_types.add type + end + scan_top_level(@top_level) + end end - scan_top_level(@top_level) @top_level end @@ -74,7 +82,7 @@ class Parser # split_module tries to find if +path+ belongs to the module path # if it does, it returns the module name, otherwise if we are sure - # it is part of the global manifest path, "<site>" is returned. + # it is part of the global manifest path, "__site__" is returned. # And finally if this path couldn't be mapped anywhere, nil is returned. def split_module(path) # find a module @@ -105,7 +113,7 @@ class Parser end # we are under a global manifests Puppet.debug "rdoc: global manifests" - "<site>" + SITE end # create documentation for the top level +container+ @@ -128,7 +136,7 @@ class Parser Puppet.debug "rdoc: scanning for #{name}" container.module_name = name - container.global=true if name == "<site>" + container.global=true if name == SITE @stats.num_modules += 1 container, name = get_class_or_module(container,name) @@ -199,19 +207,21 @@ class Parser if stmt.is_a?(Puppet::Parser::AST::Resource) and !stmt.type.nil? begin type = stmt.type.split("::").collect { |s| s.capitalize }.join("::") - title = stmt.title.is_a?(Puppet::Parser::AST::ASTArray) ? stmt.title.to_s.gsub(/\[(.*)\]/,'\1') : stmt.title.to_s - Puppet.debug "rdoc: found resource: #{type}[#{title}]" + stmt.instances.each do |inst| + title = inst.title.is_a?(Puppet::Parser::AST::ASTArray) ? inst.title.to_s.gsub(/\[(.*)\]/,'\1') : inst.title.to_s + Puppet.debug "rdoc: found resource: #{type}[#{title}]" - param = [] - stmt.params.children.each do |p| - res = {} - res["name"] = p.param - res["value"] = "#{p.value.to_s}" unless p.value.nil? + param = [] + inst.parameters.children.each do |p| + res = {} + res["name"] = p.param + res["value"] = "#{p.value.to_s}" unless p.value.nil? - param << res - end + param << res + end - container.add_resource(PuppetResource.new(type, title, stmt.doc, param)) + container.add_resource(PuppetResource.new(type, title, stmt.doc, param)) + end rescue => detail raise Puppet::ParseError, "impossible to parse resource in #{stmt.file} at line #{stmt.line}: #{detail}" end @@ -332,7 +342,7 @@ class Parser # that contains the documentation def parse_elements(container) Puppet.debug "rdoc: scanning manifest" - @ast.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass| + @known_resource_types.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass| name = klass.name if klass.file == @input_file_name unless name.empty? @@ -345,13 +355,13 @@ class Parser end end - @ast.definitions.each do |name, define| + @known_resource_types.definitions.each do |name, define| if define.file == @input_file_name document_define(name,define,container) end end - @ast.nodes.each do |name, node| + @known_resource_types.nodes.each do |name, node| if node.file == @input_file_name document_node(name.to_s,node,container) end diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb index 62bab643e..95efeb1c1 100644 --- a/lib/puppet/util/reference.rb +++ b/lib/puppet/util/reference.rb @@ -15,7 +15,7 @@ class Puppet::Util::Reference end def self.modes - %w{pdf trac text markdown} + %w{pdf text} end def self.newreference(name, options = {}, &block) @@ -32,7 +32,6 @@ class Puppet::Util::Reference section = reference(name) or raise "Could not find section #{name}" depth = section.depth if section.depth < depth end - text = ".. contents:: :depth: 2\n\n" end def self.pdf(text) @@ -40,14 +39,7 @@ class Puppet::Util::Reference Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f| f.puts text end - rst2latex = %x{which rst2latex} - if $CHILD_STATUS != 0 or rst2latex =~ /no / - rst2latex = %x{which rst2latex.py} - end - if $CHILD_STATUS != 0 or rst2latex =~ /no / - raise "Could not find rst2latex" - end - rst2latex.chomp! + rst2latex = which('rst2latex') || which('rst2latex.py') || raise("Could not find rst2latex") cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex} Puppet::Util.secure_open("/tmp/puppetdoc.tex","w") do |f| # If we get here without an error, /tmp/puppetdoc.tex isn't a tricky cracker's symlink @@ -67,38 +59,12 @@ class Puppet::Util::Reference end - def self.markdown(name, text) - puts "Creating markdown for #{name} reference." - dir = "/tmp/#{Puppet::PUPPETVERSION}" - FileUtils.mkdir(dir) unless File.directory?(dir) - Puppet::Util.secure_open(dir + "/#{name}.rst", "w") do |f| - f.puts text - end - pandoc = %x{which pandoc} - if $CHILD_STATUS != 0 or pandoc =~ /no / - pandoc = %x{which pandoc} - end - if $CHILD_STATUS != 0 or pandoc =~ /no / - raise "Could not find pandoc" - end - pandoc.chomp! - cmd = %{#{pandoc} -s -r rst -w markdown #{dir}/#{name}.rst -o #{dir}/#{name}.mdwn} - output = %x{#{cmd}} - unless $CHILD_STATUS == 0 - $stderr.puts "Pandoc failed to create #{name} reference." - $stderr.puts output - exit(1) - end - - File.unlink(dir + "/#{name}.rst") - end - def self.references instance_loader(:reference).loadall loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s } end - HEADER_LEVELS = [nil, "=", "-", "+", "'", "~"] + HEADER_LEVELS = [nil, "#", "##", "###", "####", "#####"] attr_accessor :page, :depth, :header, :title, :dynamic attr_writer :doc @@ -116,7 +82,7 @@ class Puppet::Util::Reference end def h(name, level) - "#{name}\n#{HEADER_LEVELS[level] * name.to_s.length}\n\n" + "#{HEADER_LEVELS[level]} #{name}\n\n" end def initialize(name, options = {}, &block) @@ -167,7 +133,6 @@ class Puppet::Util::Reference # First the header text = h(@title, 1) text += "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n" - text += ".. contents:: :depth: #{@depth}\n\n" if withcontents text += @header @@ -181,27 +146,4 @@ class Puppet::Util::Reference def to_text(withcontents = true) strip_trac(to_rest(withcontents)) end - - def to_trac(with_contents = true) - "{{{\n#!rst\n#{self.to_rest(with_contents)}\n}}}" - end - - def trac - Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f| - f.puts self.to_trac - end - - puts "Writing #{@name} reference to trac as #{@page}" - cmd = %{sudo trac-admin /opt/rl/trac/puppet wiki import %s /tmp/puppetdoc.txt} % self.page - output = %x{#{cmd}} - unless $CHILD_STATUS == 0 - $stderr.puts "trac-admin failed" - $stderr.puts output - exit(1) - end - unless output =~ /^\s+/ - $stderr.puts output - end - end end - diff --git a/lib/puppet/util/suidmanager.rb b/lib/puppet/util/suidmanager.rb index 4d2c32217..6633de002 100644 --- a/lib/puppet/util/suidmanager.rb +++ b/lib/puppet/util/suidmanager.rb @@ -88,7 +88,7 @@ module Puppet::Util::SUIDManager module_function :initgroups def run_and_capture(command, new_uid=nil, new_gid=nil) - output = Puppet::Util.execute(command, :failonfail => false, :uid => new_uid, :gid => new_gid) + output = Puppet::Util.execute(command, :failonfail => false, :combine => true, :uid => new_uid, :gid => new_gid) [output, $CHILD_STATUS.dup] end module_function :run_and_capture diff --git a/lib/puppet/util/zaml.rb b/lib/puppet/util/zaml.rb index 8ecc2c8bd..2155e989c 100644 --- a/lib/puppet/util/zaml.rb +++ b/lib/puppet/util/zaml.rb @@ -29,7 +29,8 @@ class ZAML @result = [] @indent = nil @structured_key_prefix = nil - Label.counter_reset + @previously_emitted_object = {} + @next_free_label_number = 0 emit('--- ') end def nested(tail=' ') @@ -55,31 +56,29 @@ class ZAML # which we will encounter a reference to the object as we serialize # it can be handled). # - def self.counter_reset - @@previously_emitted_object = {} - @@next_free_label_number = 0 - end + attr_accessor :this_label_number def initialize(obj,indent) @indent = indent @this_label_number = nil - @@previously_emitted_object[obj.object_id] = self end def to_s @this_label_number ? ('&id%03d%s' % [@this_label_number, @indent]) : '' end def reference - @this_label_number ||= (@@next_free_label_number += 1) @reference ||= '*id%03d' % @this_label_number end - def self.for(obj) - @@previously_emitted_object[obj.object_id] - end + end + def label_for(obj) + @previously_emitted_object[obj.object_id] end def new_label_for(obj) - Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"} " : ' ') + label = Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"} " : ' ') + @previously_emitted_object[obj.object_id] = label + label end def first_time_only(obj) - if label = Label.for(obj) + if label = label_for(obj) + label.this_label_number ||= (@next_free_label_number += 1) emit(label.reference) else if @structured_key_prefix and not obj.is_a? String @@ -120,6 +119,9 @@ class Object def to_yaml_properties instance_variables.sort # Default YAML behavior end + def yaml_property_munge(x) + x + end def zamlized_class_name(root) cls = self.class "!ruby/#{root.name.downcase}#{cls == root ? '' : ":#{cls.respond_to?(:name) ? cls.name : cls}"}" @@ -136,7 +138,7 @@ class Object z.nl v[1..-1].to_zaml(z) # Remove leading '@' z.emit(': ') - instance_variable_get(v).to_zaml(z) + yaml_property_munge(instance_variable_get(v)).to_zaml(z) } end } @@ -243,7 +245,6 @@ class String when self =~ /\n/ if self[-1..-1] == "\n" then z.emit('|+') else z.emit('|-') end z.nested { split("\n",-1).each { |line| z.nl; z.emit(line.chomp("\n")) } } - z.nl else z.emit(self) end |
