diff options
185 files changed, 5055 insertions, 4039 deletions
@@ -43,7 +43,7 @@ desc "Create the tarball and the gem - use when releasing" task :puppetpackages => [:create_gem, :package] Spec::Rake::SpecTask.new do |t| - t.spec_opts = ['--format','s', '--loadby','mtime','--color'] + t.spec_opts = ['--format','s', '--loadby','mtime','--color', '--backtrace'] t.pattern ='spec/{unit,integration}/**/*.rb' t.fail_on_error = false end diff --git a/ext/cert_inspector b/ext/cert_inspector new file mode 100755 index 000000000..1effcaa04 --- /dev/null +++ b/ext/cert_inspector @@ -0,0 +1,140 @@ +#!/usr/bin/env ruby +require 'openssl' + +class X509Collector + include Enumerable + + def initialize + @collected_data = {} + end + + def interpret_contents(contents) + cls = case contents.split("\n")[0] + when /BEGIN X509 CRL/ then OpenSSL::X509::CRL + when /BEGIN CERTIFICATE REQUEST/ then OpenSSL::X509::Request + when /BEGIN CERTIFICATE/ then OpenSSL::X509::Certificate + when /BEGIN RSA (PRIVATE|PUBLIC) KEY/ then OpenSSL::PKey::RSA + else return nil + end + cls.new(contents) + rescue + nil + end + + def expected_non_x509_files + ['inventory.txt', 'ca.pass', 'serial'] + end + + def investigate_path(path) + if File.directory?(path) + Dir.foreach(path) do |x| + next if ['.', '..'].include? x + investigate_path File.join(path, x) + end + else + contents = File.read path + meaning = interpret_contents contents + unless meaning || expected_non_x509_files.include?(File.basename(path)) + puts "WARNING: file #{path.inspect} could not be interpreted" + end + @collected_data[path] = meaning if meaning + end + end + + def each(&block) + @collected_data.each(&block) + end + + def extract_public_key_info(path, meaning) + case meaning + when OpenSSL::PKey::RSA + if meaning.private? + [meaning.public_key, 2, path] + else + [meaning, 3, path] + end + when OpenSSL::X509::Certificate + [meaning.public_key, 0, meaning.subject.to_s] + when OpenSSL::X509::Request + [meaning.public_key, 1, meaning.subject.to_s] + end + end + + def who_signed(meaning, key_names, keys) + signing_key = keys.find { |key| meaning.verify(key) } + if signing_key then "#{key_names[signing_key.to_s]}" else "???" end + end + + def explain(meaning, key_names, keys) + case meaning + when OpenSSL::PKey::RSA + if meaning.private? + "Private key for #{key_names[meaning.public_key.to_s]}" + else + "Public key for #{key_names[meaning.public_key.to_s]}" + end + when OpenSSL::X509::Certificate + signature_desc = who_signed(meaning, key_names, keys) + "Certificate assigning name #{meaning.subject.to_s} to #{key_names[meaning.public_key.to_s]}\n serial number #{meaning.serial}\n issued by #{meaning.issuer.to_s}\n signed by #{signature_desc}" + when OpenSSL::X509::Request + signature_desc = who_signed(meaning, key_names, keys) + "Certificate request for #{meaning.subject.to_s} having key #{key_names[meaning.public_key.to_s]}\n signed by #{signature_desc}" + when OpenSSL::X509::CRL + signature_desc = who_signed(meaning, key_names, keys) + revoked_serial_numbers = meaning.revoked.map { |r| r.serial } + revoked_desc = if revoked_serial_numbers.count > 0 then "serial numbers #{revoked_serial_numbers.inspect}" else "nothing" end + "Certificate revocation list revoking #{revoked_desc}\n issued by #{meaning.issuer.to_s}\n signed by #{signature_desc}" + else + "Unknown" + end + end + + # Yield unique public keys, with a canonical name for each. + def collect_public_keys + key_data = {} # pem => (priority, name, public_key) + @collected_data.collect do |path, meaning| + begin + next unless public_key_info = extract_public_key_info(path, meaning) + public_key, priority, name = public_key_info + pem = public_key.to_s + existing_priority, existing_name, existing_public_key = key_data[pem] + next if existing_priority and existing_priority < priority + key_data[pem] = priority, name, public_key + rescue + puts "exception!" + end + end + name_to_key_hash = {} + key_data.each do |pem, data| + priority, name, public_key = data + if name_to_key_hash[name] + suffix_num = 2 + while name_to_key_hash[name + " (#{suffix_num})"] + suffix_num += 1 + end + name = name + " (#{suffix_num})" + end + name_to_key_hash[name] = public_key + end + key_names = {} + keys = [] + name_to_key_hash.each do |name, public_key| + key_names[public_key.to_s] = "key<#{name}>" + keys << public_key + end + [key_names, keys] + end +end + +collector = X509Collector.new +ARGV.each do |path| + collector.investigate_path(path) +end +key_names, keys = collector.collect_public_keys +collector.map do |path, meaning| + [collector.explain(meaning, key_names, keys), path] +end.sort.each do |description, path| + puts "#{path}:" + puts " #{description}" + puts +end diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb index 2b75505fd..96f33296f 100644 --- a/lib/puppet/application/agent.rb +++ b/lib/puppet/application/agent.rb @@ -228,7 +228,9 @@ class Puppet::Application::Agent < Puppet::Application # 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 + Puppet::Transaction::Report.indirection.terminus_class = :rest + # we want the last report to be persisted locally + Puppet::Transaction::Report.indirection.cache_class = :yaml # Override the default; puppetd needs this, usually. # You can still override this on the command-line with, e.g., :compiler. @@ -237,8 +239,7 @@ class Puppet::Application::Agent < Puppet::Application # Override the default. Puppet[:facts_terminus] = :facter - Puppet::Resource::Catalog.cache_class = :yaml - + Puppet::Resource::Catalog.indirection.cache_class = :yaml # We need tomake the client either way, we just don't start it # if --no-client is set. diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb index 59a95d35a..e5b4bb5b7 100644 --- a/lib/puppet/application/apply.rb +++ b/lib/puppet/application/apply.rb @@ -85,12 +85,12 @@ class Puppet::Application::Apply < Puppet::Application end # Collect our facts. - unless facts = Puppet::Node::Facts.find(Puppet[:certname]) + unless facts = Puppet::Node::Facts.indirection.find(Puppet[:certname]) raise "Could not find facts for #{Puppet[:certname]}" end # Find our Node - unless node = Puppet::Node.find(Puppet[:certname]) + unless node = Puppet::Node.indirection.find(Puppet[:certname]) raise "Could not find node #{Puppet[:certname]}" end @@ -112,7 +112,7 @@ class Puppet::Application::Apply < Puppet::Application begin # Compile our catalog starttime = Time.now - catalog = Puppet::Resource::Catalog.find(node.name, :use_node => node) + catalog = Puppet::Resource::Catalog.indirection.find(node.name, :use_node => node) # Translate it to a RAL catalog catalog = catalog.to_ral @@ -123,25 +123,9 @@ class Puppet::Application::Apply < Puppet::Application require 'puppet/configurer' configurer = Puppet::Configurer.new - configurer.execute_prerun_command + report = configurer.run(:skip_plugin_download => true, :catalog => catalog) - # And apply it - if Puppet[:report] - report = configurer.initialize_report - Puppet::Util::Log.newdestination(report) - end - transaction = catalog.apply - - configurer.execute_postrun_command - - if Puppet[:report] - Puppet::Util::Log.close(report) - configurer.send_report(report, transaction) - else - transaction.generate_report - end - - exit( Puppet[:noop] ? 0 : options[:detailed_exitcodes] ? transaction.report.exit_status : 0 ) + exit( Puppet[:noop] ? 0 : options[:detailed_exitcodes] ? report.exit_status : 0 ) rescue => detail puts detail.backtrace if Puppet[:trace] $stderr.puts detail.message @@ -164,6 +148,9 @@ class Puppet::Application::Apply < Puppet::Application exit(1) end + # we want the last report to be persisted locally + Puppet::Transaction::Report.indirection.cache_class = :yaml + if options[:debug] Puppet::Util::Log.level = :debug elsif options[:verbose] diff --git a/lib/puppet/application/kick.rb b/lib/puppet/application/kick.rb index 37aeb1ef2..12dad653a 100644 --- a/lib/puppet/application/kick.rb +++ b/lib/puppet/application/kick.rb @@ -120,7 +120,7 @@ class Puppet::Application::Kick < Puppet::Application :background => ! options[:foreground], :ignoreschedules => options[:ignoreschedules] } - run = Puppet::Run.new( run_options ).save( url ) + run = Puppet::Run.indirection.save(Puppet::Run.new( run_options ), url) puts "Getting status" result = run.status puts "status is #{result}" @@ -175,12 +175,12 @@ class Puppet::Application::Kick < Puppet::Application if Puppet[:node_terminus] == "ldap" and (options[:all] or @classes) if options[:all] - @hosts = Puppet::Node.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name } + @hosts = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name } puts "all: #{@hosts.join(", ")}" else @hosts = [] @classes.each do |klass| - list = Puppet::Node.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name } + list = Puppet::Node.indirection.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name } puts "#{klass}: #{list.join(", ")}" @hosts += list diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb index fde474907..879b66c67 100644 --- a/lib/puppet/application/master.rb +++ b/lib/puppet/application/master.rb @@ -51,7 +51,7 @@ class Puppet::Application::Master < Puppet::Application Puppet::Util::Log.newdestination :console raise ArgumentError, "Cannot render compiled catalogs without pson support" unless Puppet.features.pson? begin - unless catalog = Puppet::Resource::Catalog.find(options[:node]) + unless catalog = Puppet::Resource::Catalog.indirection.find(options[:node]) raise "Could not compile catalog for #{options[:node]}" end @@ -139,7 +139,7 @@ class Puppet::Application::Master < Puppet::Application Puppet.settings.use :main, :master, :ssl # Cache our nodes in yaml. Currently not configurable. - Puppet::Node.cache_class = :yaml + Puppet::Node.indirection.cache_class = :yaml # Configure all of the SSL stuff. if Puppet::SSL::CertificateAuthority.ca? diff --git a/lib/puppet/application/queue.rb b/lib/puppet/application/queue.rb index 239f6b2ad..b9e8ca4ca 100644 --- a/lib/puppet/application/queue.rb +++ b/lib/puppet/application/queue.rb @@ -41,12 +41,12 @@ class Puppet::Application::Queue < Puppet::Application 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 + # Once you have a Puppet::Resource::Catalog instance, passing it to save should suffice # to put it through to the database via its active_record indirector (which is determined # by the terminus_class = :active_record setting above) Puppet::Util.benchmark(:notice, "Processing queued catalog for #{catalog.name}") do begin - catalog.save + Puppet::Resource::Catalog.indirection.save(catalog) rescue => detail puts detail.backtrace if Puppet[:trace] Puppet.err "Could not save queued catalog for #{catalog.name}: #{detail}" @@ -79,7 +79,7 @@ class Puppet::Application::Queue < Puppet::Application exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs? require 'puppet/resource/catalog' - Puppet::Resource::Catalog.terminus_class = :active_record + Puppet::Resource::Catalog.indirection.terminus_class = :active_record daemon.daemonize if Puppet[:daemonize] @@ -87,6 +87,6 @@ class Puppet::Application::Queue < Puppet::Application # class set up, because if storeconfigs is enabled, # we'll get a loop of continually caching the catalog # for storage again. - Puppet::Resource::Catalog.cache_class = nil + Puppet::Resource::Catalog.indirection.cache_class = nil end end diff --git a/lib/puppet/application/resource.rb b/lib/puppet/application/resource.rb index f55caa58a..c7c1c28be 100644 --- a/lib/puppet/application/resource.rb +++ b/lib/puppet/application/resource.rb @@ -76,12 +76,12 @@ class Puppet::Application::Resource < Puppet::Application text = if name if params.empty? - [ Puppet::Resource.find( key ) ] + [ Puppet::Resource.indirection.find( key ) ] else - [ Puppet::Resource.new( type, name, :parameters => params ).save( key ) ] + [ Puppet::Resource.indirection.save(Puppet::Resource.new( type, name, :parameters => params ), key) ] end else - Puppet::Resource.search( key, {} ) + Puppet::Resource.indirection.search( key, {} ) end.map(&format).join("\n") if options[:edit] diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb index 31d31c2d2..50aaa0d1f 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 @@ -168,19 +168,30 @@ class Puppet::Configurer 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] + Puppet::Transaction::Report.indirection.save(report) + 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 @@ -213,7 +224,7 @@ class Puppet::Configurer def retrieve_catalog_from_cache(fact_options) result = nil @duration = thinmark do - result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_terminus => true)) + result = Puppet::Resource::Catalog.indirection.find(Puppet[:certname], fact_options.merge(:ignore_terminus => true)) end Puppet.notice "Using cached catalog" result @@ -226,7 +237,7 @@ class Puppet::Configurer def retrieve_new_catalog(fact_options) result = nil @duration = thinmark do - result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_cache => true)) + result = Puppet::Resource::Catalog.indirection.find(Puppet[:certname], fact_options.merge(:ignore_cache => true)) end result rescue SystemExit,NoMemoryError diff --git a/lib/puppet/configurer/fact_handler.rb b/lib/puppet/configurer/fact_handler.rb index 075a59458..abe032010 100644 --- a/lib/puppet/configurer/fact_handler.rb +++ b/lib/puppet/configurer/fact_handler.rb @@ -16,7 +16,7 @@ module Puppet::Configurer::FactHandler # compile them and then "cache" them on the server. begin reload_facter - Puppet::Node::Facts.find(Puppet[:certname]) + Puppet::Node::Facts.indirection.find(Puppet[:certname]) rescue SystemExit,NoMemoryError raise rescue Exception => detail diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 4521a5901..1e7229d01 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -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 => [Puppet.application_name.to_s == "master" ? 'yaml' : 'facter', "The node facts terminus."], + :facts_terminus => { + :default => Puppet.application_name.to_s == "master" ? 'yaml' : 'facter', + :desc => "The node facts terminus.", + :hook => proc do |value| + require 'puppet/node/facts' + if value.to_s == "rest" + Puppet::Node::Facts.indirection.cache_class = :yaml + end + end + }, + :inventory_terminus => [ "$facts_terminus", "Should usually be the same as the facts terminus" ], :httplog => { :default => "$logdir/http.log", :owner => "root", :mode => 0640, @@ -142,7 +152,7 @@ module Puppet Puppet.settings[:storeconfigs] = true # But then we modify the configuration - Puppet::Resource::Catalog.cache_class = :queue + Puppet::Resource::Catalog.indirection.cache_class = :queue else raise "Cannot disable asynchronous storeconfigs in a running process" end @@ -578,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)."], @@ -770,9 +794,9 @@ module Puppet if value require 'puppet/rails' raise "StoreConfigs not supported without ActiveRecord 2.1 or higher" unless Puppet.features.rails? - Puppet::Resource::Catalog.cache_class = :active_record unless Puppet.settings[:async_storeconfigs] - Puppet::Node::Facts.cache_class = :active_record - Puppet::Node.cache_class = :active_record + Puppet::Resource::Catalog.indirection.cache_class = :active_record unless Puppet.settings[:async_storeconfigs] + Puppet::Node::Facts.indirection.cache_class = :active_record + Puppet::Node.indirection.cache_class = :active_record end end } diff --git a/lib/puppet/dsl/resource_type_api.rb b/lib/puppet/dsl/resource_type_api.rb index ecb914189..8810d5368 100644 --- a/lib/puppet/dsl/resource_type_api.rb +++ b/lib/puppet/dsl/resource_type_api.rb @@ -1,46 +1,34 @@ require 'puppet/resource/type' +# 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 define(name, *args, &block) - result = __mk_resource_type__(:definition, name, Hash.new, block) - result.set_arguments(__munge_type_arguments__(args)) + args = args.inject([]) do |result, item| + if item.is_a?(Hash) + item.each { |p, v| result << [p, v] } + else + result << item + end + result + end + @__created_ast_objects__.push Puppet::Parser::AST::Definition.new(name, {:arguments => args}, &block) nil end def hostclass(name, options = {}, &block) - __mk_resource_type__(:hostclass, name, options, block) + @__created_ast_objects__.push Puppet::Parser::AST::Hostclass.new(name, options, &block) nil end def node(name, options = {}, &block) - __mk_resource_type__(: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 - - # Note: we don't want the user to call the following methods - # directly. However, we can't stop them by making the methods - # private because the user's .rb code gets instance_eval'ed on an - # instance of this class. So instead we name the methods using - # double underscores to discourage customers from calling them. - - def __mk_resource_type__(type, name, options, code) - klass = Puppet::Resource::Type.new(type, name, options) - - klass.ruby_code = code if code - - Thread.current[:known_resource_types].add klass - - klass - end - - def __munge_type_arguments__(args) - args.inject([]) do |result, item| - if item.is_a?(Hash) - item.each { |p, v| result << [p, v] } - else - result << item - end - result - end - end end diff --git a/lib/puppet/external/pson/pure/generator.rb b/lib/puppet/external/pson/pure/generator.rb index 4180be57d..89a0c62e0 100644 --- a/lib/puppet/external/pson/pure/generator.rb +++ b/lib/puppet/external/pson/pure/generator.rb @@ -44,34 +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. - gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] }. - gsub(/((?: - [\xc2-\xdf][\x80-\xbf] | - [\xe0-\xef][\x80-\xbf]{2} | - [\xf0-\xf4][\x80-\xbf]{3} - )+)/nx) { |c| - PSON::UTF8toUTF16.iconv(c).unpack('H*')[0].gsub(/.{4}/n, '\\\\u\&') - } + string.gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] } end end module_function :utf8_to_pson diff --git a/lib/puppet/file_bucket/dipper.rb b/lib/puppet/file_bucket/dipper.rb index dbfcdcd43..367d6bfbd 100644 --- a/lib/puppet/file_bucket/dipper.rb +++ b/lib/puppet/file_bucket/dipper.rb @@ -36,7 +36,7 @@ class Puppet::FileBucket::Dipper file_bucket_file = Puppet::FileBucket::File.new(contents, :bucket_path => @local_path, :path => absolutize_path(file) ) dest_path = "#{@rest_path}#{file_bucket_file.name}" - file_bucket_file.save(dest_path) + Puppet::FileBucket::File.indirection.save(file_bucket_file, dest_path) return file_bucket_file.checksum_data rescue => detail puts detail.backtrace if Puppet[:trace] @@ -47,7 +47,7 @@ class Puppet::FileBucket::Dipper # Retrieve a file by sum. def getfile(sum) source_path = "#{@rest_path}md5/#{sum}" - file_bucket_file = Puppet::FileBucket::File.find(source_path, :bucket_path => @local_path) + file_bucket_file = Puppet::FileBucket::File.indirection.find(source_path, :bucket_path => @local_path) raise Puppet::Error, "File not found" unless file_bucket_file file_bucket_file.to_s diff --git a/lib/puppet/indirector.rb b/lib/puppet/indirector.rb index 5b737578b..9effc5cdd 100644 --- a/lib/puppet/indirector.rb +++ b/lib/puppet/indirector.rb @@ -21,7 +21,6 @@ module Puppet::Indirector raise(ArgumentError, "Already handling indirection for #{@indirection.name}; cannot also handle #{indirection}") if @indirection # populate this class with the various new methods extend ClassMethods - include InstanceMethods include Puppet::Indirector::Envelope extend Puppet::Network::FormatHandler @@ -32,36 +31,5 @@ module Puppet::Indirector module ClassMethods attr_reader :indirection - - def cache_class=(klass) - indirection.cache_class = klass - end - - def terminus_class=(klass) - indirection.terminus_class = klass - end - - # Expire any cached instance. - def expire(*args) - indirection.expire(*args) - end - - def find(*args) - indirection.find(*args) - end - - def destroy(*args) - indirection.destroy(*args) - end - - def search(*args) - indirection.search(*args) - end - end - - module InstanceMethods - def save(key = nil) - self.class.indirection.save key, self - end end end diff --git a/lib/puppet/indirector/catalog/active_record.rb b/lib/puppet/indirector/catalog/active_record.rb index fabb08eb9..5157fb538 100644 --- a/lib/puppet/indirector/catalog/active_record.rb +++ b/lib/puppet/indirector/catalog/active_record.rb @@ -30,7 +30,7 @@ class Puppet::Resource::Catalog::ActiveRecord < Puppet::Indirector::ActiveRecord host.merge_resources(catalog.vertices) host.last_compile = Time.now - if node = Puppet::Node.find(catalog.name) + if node = Puppet::Node.indirection.find(catalog.name) host.ip = node.parameters["ipaddress"] host.environment = node.environment end diff --git a/lib/puppet/indirector/catalog/compiler.rb b/lib/puppet/indirector/catalog/compiler.rb index 6375e801f..f4c40812d 100644 --- a/lib/puppet/indirector/catalog/compiler.rb +++ b/lib/puppet/indirector/catalog/compiler.rb @@ -22,7 +22,8 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code else facts = Puppet::Node::Facts.convert_from(format, text_facts) end - facts.save + facts.add_timestamp + Puppet::Node::Facts.indirection.save(facts) end # Compile a node's catalog. @@ -87,7 +88,7 @@ class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code # Turn our host name into a node object. def find_node(name) begin - return nil unless node = Puppet::Node.find(name) + return nil unless node = Puppet::Node.indirection.find(name) rescue => detail puts detail.backtrace if Puppet[:trace] raise Puppet::Error, "Failed when searching for node #{name}: #{detail}" 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..eb0aa8aee 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 @@ -246,7 +247,7 @@ class Puppet::Indirector::Indirection # Save the instance in the appropriate terminus. This method is # normally an instance method on the indirected class. - def save(key, instance = nil) + def save(instance, key = nil) request = request(:save, key, instance) terminus = prepare(request) 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/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/network/handler/filebucket.rb b/lib/puppet/network/handler/filebucket.rb index 6aaa2df1c..55028ee64 100755 --- a/lib/puppet/network/handler/filebucket.rb +++ b/lib/puppet/network/handler/filebucket.rb @@ -28,12 +28,12 @@ class Puppet::Network::Handler # :nodoc: def addfile(contents, path, client = nil, clientip = nil) contents = Base64.decode64(contents) if client bucket = Puppet::FileBucket::File.new(contents) - bucket.save + Puppet::FileBucket::File.indirection.save(bucket) end # Return the contents associated with a given md5 sum. def getfile(md5, client = nil, clientip = nil) - bucket = Puppet::FileBucket::File.find("md5:#{md5}") + bucket = Puppet::FileBucket::File.indirection.find("md5:#{md5}") contents = bucket.contents if client diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb index 1531f4f5c..5b4b17a32 100755 --- a/lib/puppet/network/handler/fileserver.rb +++ b/lib/puppet/network/handler/fileserver.rb @@ -4,11 +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 @@ -234,7 +236,7 @@ class Puppet::Network::Handler unless hostname = (client || Facter.value("hostname")) raise ArgumentError, "Could not find hostname" end - env = (node = Puppet::Node.find(hostname)) ? node.environment : nil + env = (node = Puppet::Node.indirection.find(hostname)) ? node.environment : nil # And use the environment to look up the module. (mod = Puppet::Node::Environment.new(env).module(module_name) and mod.files?) ? @mounts[MODULES].copy(mod.name, mod.file_directory) : nil diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb index c21aafafc..62aab539e 100644 --- a/lib/puppet/network/handler/master.rb +++ b/lib/puppet/network/handler/master.rb @@ -47,9 +47,9 @@ class Puppet::Network::Handler client ||= facts["hostname"] # Pass the facts to the fact handler - Puppet::Node::Facts.new(client, facts).save unless local? + Puppet::Node::Facts.indirection.save(Puppet::Node::Facts.new(client, facts)) unless local? - catalog = Puppet::Resource::Catalog.find(client) + catalog = Puppet::Resource::Catalog.indirection.find(client) case format when "yaml" 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 61ae2d2fc..916f02c8d 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).indirection.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.indirection.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.key}'", 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).indirection.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 = model(indirection_name).indirection.save(obj, 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/webrick.rb b/lib/puppet/network/http/webrick.rb index 8ed0b28ca..54bcf30c2 100644 --- a/lib/puppet/network/http/webrick.rb +++ b/lib/puppet/network/http/webrick.rb @@ -105,7 +105,7 @@ class Puppet::Network::HTTP::WEBrick results[:SSLStartImmediately] = true results[:SSLEnable] = true - raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.find(Puppet::SSL::CA_NAME) + raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.indirection.find(Puppet::SSL::CA_NAME) results[:SSLCACertificateFile] = Puppet[:localcacert] results[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb index 7abe06956..850f9211c 100644 --- a/lib/puppet/network/rest_authconfig.rb +++ b/lib/puppet/network/rest_authconfig.rb @@ -31,21 +31,21 @@ module Puppet # 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) @@ -89,8 +89,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/node.rb b/lib/puppet/node.rb index 2453cd1d5..5b0a98615 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 @@ -56,7 +57,7 @@ class Puppet::Node # Merge the node facts with parameters from the node source. def fact_merge - if facts = Puppet::Node::Facts.find(name) + if facts = Puppet::Node::Facts.indirection.find(name) merge(facts.values) end rescue => detail diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index b64fb8a1f..7877b7f73 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -81,7 +81,7 @@ class Puppet::Node::Environment 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.perform_initial_import + @known_resource_types.import_ast(perform_initial_import, '') end @known_resource_types } @@ -147,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..451813f7d 100755 --- a/lib/puppet/node/facts.rb +++ b/lib/puppet/node/facts.rb @@ -1,17 +1,22 @@ +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 - def save(key, instance) - Puppet::Node.expire(instance.name) + def save(instance, key = nil) + Puppet::Node.indirection.expire(instance.name) super end end @@ -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/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/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/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/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 b019e6aac..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,46 +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. - fully_qualified_type, resource_titles = scope.resolve_type_and_titles(type, resource_titles) + # 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_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 - ) + # Evaluate all of the specified params. + paramobjects = instance.parameters.collect { |param| + param.safeevaluate(scope) + } - 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 - }.reject { |resource| resource.nil? } - end + resource_titles = instance.title.safeevaluate(scope) - # Set the parameters for our object. - def parameters=(params) - if params.is_a?(AST::ASTArray) - @parameters = params - else - @parameters = AST::ASTArray.new( - :line => params.line, - :file => params.file, - :children => [params] - ) - end + # 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) + + # 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 + ) + + 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/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/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/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 7bbebb124..746aa0f90 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -29,18 +29,9 @@ 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 @@ -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,11 +94,11 @@ 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) @@ -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,42 +145,42 @@ 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 @@ -217,7 +188,11 @@ class Puppet::Parser::Parser def parse_ruby_file # Execute the contents of the file inside its own "main" object so # that it can call methods in the resource type API. - Puppet::DSL::ResourceTypeAPI.new.instance_eval(File.read(self.file)) + 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/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 bae560381..140c9f2ca 100644 --- a/lib/puppet/parser/type_loader.rb +++ b/lib/puppet/parser/type_loader.rb @@ -78,16 +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 @loading_helper.do_once(file) do - parse_file(file) + loaded_asts << parse_file(file) end end - - modname + loaded_asts.inject([]) do |loaded_types, ast| + loaded_types + known_resource_types.import_ast(ast, modname) + end end def known_resource_types @@ -99,50 +101,45 @@ class Puppet::Parser::TypeLoader @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(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.debug "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 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 + + 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/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb index 7dbd06240..461968245 100644 --- a/lib/puppet/provider/augeas/augeas.rb +++ b/lib/puppet/provider/augeas/augeas.rb @@ -213,7 +213,12 @@ Puppet::Type.type(:augeas).provide(:augeas) do fail("Invalid command: #{cmd_array.join(" ")}") if clause_array.length != 2 comparator = clause_array.shift arg = clause_array.shift - return_value = (result.size.send(comparator, arg)) + case comparator + when "!=" + return_value = !(result.size.send(:==, arg)) + else + return_value = (result.size.send(comparator, arg)) + end when "include" arg = clause_array.shift return_value = result.include?(arg) 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/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/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/package/yum.rb b/lib/puppet/provider/package/yum.rb index fcda5ba8c..6ed966fbd 100755 --- a/lib/puppet/provider/package/yum.rb +++ b/lib/puppet/provider/package/yum.rb @@ -1,3 +1,4 @@ +require 'puppet/util/package' Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do desc "Support via `yum`." @@ -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/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/resource/type.rb b/lib/puppet/resource/type.rb index d40adc145..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 } @@ -92,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 diff --git a/lib/puppet/resource/type_collection.rb b/lib/puppet/resource/type_collection.rb index 63d110395..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 name =~ /^::/ - return send(type, name.sub(/^::/, '')) - 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,24 +116,6 @@ class Puppet::Resource::TypeCollection end end - def perform_initial_import - return if Puppet.settings[:ignoreimport] - 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 @@ -198,8 +144,52 @@ class Puppet::Resource::TypeCollection private - def find_partially_qualified(namespace, name, type) - send(type, [namespace, name].join("::")) + # 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 + + # 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 55b39fadf..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 @@ -381,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 @@ -422,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] @@ -445,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_authority.rb b/lib/puppet/ssl/certificate_authority.rb index 0c226ca6a..d65067c70 100644 --- a/lib/puppet/ssl/certificate_authority.rb +++ b/lib/puppet/ssl/certificate_authority.rb @@ -63,7 +63,7 @@ class Puppet::SSL::CertificateAuthority store = nil store = autosign_store(auto) if auto != true - Puppet::SSL::CertificateRequest.search("*").each do |csr| + Puppet::SSL::CertificateRequest.indirection.search("*").each do |csr| sign(csr.name) if auto == true or store.allowed?(csr.name, "127.1.1.1") end end @@ -93,10 +93,10 @@ class Puppet::SSL::CertificateAuthority # Retrieve (or create, if necessary) the certificate revocation list. def crl unless defined?(@crl) - unless @crl = Puppet::SSL::CertificateRevocationList.find(Puppet::SSL::CA_NAME) + unless @crl = Puppet::SSL::CertificateRevocationList.indirection.find(Puppet::SSL::CA_NAME) @crl = Puppet::SSL::CertificateRevocationList.new(Puppet::SSL::CA_NAME) @crl.generate(host.certificate.content, host.key.content) - @crl.save + Puppet::SSL::CertificateRevocationList.indirection.save(@crl) end end @crl @@ -109,7 +109,7 @@ class Puppet::SSL::CertificateAuthority # Generate a new certificate. def generate(name) - raise ArgumentError, "A Certificate already exists for #{name}" if Puppet::SSL::Certificate.find(name) + raise ArgumentError, "A Certificate already exists for #{name}" if Puppet::SSL::Certificate.indirection.find(name) host = Puppet::SSL::Host.new(name) host.generate_certificate_request @@ -169,7 +169,7 @@ class Puppet::SSL::CertificateAuthority # List all signed certificates. def list - Puppet::SSL::Certificate.search("*").collect { |c| c.name } + Puppet::SSL::Certificate.indirection.search("*").collect { |c| c.name } end # Read the next serial from the serial file, and increment the @@ -199,14 +199,14 @@ class Puppet::SSL::CertificateAuthority # Print a given host's certificate as text. def print(name) - (cert = Puppet::SSL::Certificate.find(name)) ? cert.to_text : nil + (cert = Puppet::SSL::Certificate.indirection.find(name)) ? cert.to_text : nil end # Revoke a given certificate. def revoke(name) raise ArgumentError, "Cannot revoke certificates when the CRL is disabled" unless crl - if cert = Puppet::SSL::Certificate.find(name) + if cert = Puppet::SSL::Certificate.indirection.find(name) serial = cert.content.serial elsif ! serial = inventory.serial(name) raise ArgumentError, "Could not find a serial number for #{name}" @@ -229,7 +229,7 @@ class Puppet::SSL::CertificateAuthority csr = self_signing_csr issuer = csr.content else - unless csr = Puppet::SSL::CertificateRequest.find(hostname) + unless csr = Puppet::SSL::CertificateRequest.indirection.find(hostname) raise ArgumentError, "Could not find certificate request for #{hostname}" end issuer = host.certificate.content @@ -248,17 +248,17 @@ class Puppet::SSL::CertificateAuthority # Save the now-signed cert. This should get routed correctly depending # on the certificate type. - cert.save + Puppet::SSL::Certificate.indirection.save(cert) # And remove the CSR if this wasn't self signed. - Puppet::SSL::CertificateRequest.destroy(csr.name) unless self_signing_csr + Puppet::SSL::CertificateRequest.indirection.destroy(csr.name) unless self_signing_csr cert end # Verify a given host's certificate. def verify(name) - unless cert = Puppet::SSL::Certificate.find(name) + unless cert = Puppet::SSL::Certificate.indirection.find(name) raise ArgumentError, "Could not find a certificate for #{name}" end store = OpenSSL::X509::Store.new @@ -271,7 +271,7 @@ class Puppet::SSL::CertificateAuthority end def fingerprint(name, md = :MD5) - unless cert = Puppet::SSL::Certificate.find(name) || Puppet::SSL::CertificateRequest.find(name) + unless cert = Puppet::SSL::Certificate.indirection.find(name) || Puppet::SSL::CertificateRequest.indirection.find(name) raise ArgumentError, "Could not find a certificate or csr for #{name}" end cert.fingerprint(md) @@ -279,6 +279,6 @@ class Puppet::SSL::CertificateAuthority # List the waiting certificate requests. def waiting? - Puppet::SSL::CertificateRequest.search("*").collect { |r| r.name } + Puppet::SSL::CertificateRequest.indirection.search("*").collect { |r| r.name } end end diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb index 2f6cae3f5..8c83339a1 100644 --- a/lib/puppet/ssl/certificate_request.rb +++ b/lib/puppet/ssl/certificate_request.rb @@ -5,7 +5,20 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base wraps OpenSSL::X509::Request extend Puppet::Indirector - indirects :certificate_request, :terminus_class => :file + + # If auto-signing is on, sign any certificate requests as they are saved. + module AutoSigner + def save(instance, key = nil) + super + + # Try to autosign the CSR. + if ca = Puppet::SSL::CertificateAuthority.instance + ca.autosign + end + end + end + + indirects :certificate_request, :terminus_class => :file, :extend => AutoSigner # Convert a string into an instance. def self.from_s(string) @@ -46,13 +59,4 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}" @content end - - def save(args = {}) - super() - - # Try to autosign the CSR. - if ca = Puppet::SSL::CertificateAuthority.instance - ca.autosign - end - end end diff --git a/lib/puppet/ssl/certificate_revocation_list.rb b/lib/puppet/ssl/certificate_revocation_list.rb index 44e0a9e22..293f4b8c0 100644 --- a/lib/puppet/ssl/certificate_revocation_list.rb +++ b/lib/puppet/ssl/certificate_revocation_list.rb @@ -79,6 +79,6 @@ class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base @content.sign(cakey, OpenSSL::Digest::SHA1.new) - save + Puppet::SSL::CertificateRevocationList.indirection.save(self) end end diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb index 8a6f0aa6d..7f71ced99 100644 --- a/lib/puppet/ssl/host.rb +++ b/lib/puppet/ssl/host.rb @@ -43,31 +43,31 @@ class Puppet::SSL::Host # Configure how our various classes interact with their various terminuses. def self.configure_indirection(terminus, cache = nil) - Certificate.terminus_class = terminus - CertificateRequest.terminus_class = terminus - CertificateRevocationList.terminus_class = terminus + Certificate.indirection.terminus_class = terminus + CertificateRequest.indirection.terminus_class = terminus + CertificateRevocationList.indirection.terminus_class = terminus if cache # This is weird; we don't actually cache our keys, we # use what would otherwise be the cache as our normal # terminus. - Key.terminus_class = cache + Key.indirection.terminus_class = cache else - Key.terminus_class = terminus + Key.indirection.terminus_class = terminus end if cache - Certificate.cache_class = cache - CertificateRequest.cache_class = cache - CertificateRevocationList.cache_class = cache + Certificate.indirection.cache_class = cache + CertificateRequest.indirection.cache_class = cache + CertificateRevocationList.indirection.cache_class = cache else # Make sure we have no cache configured. puppet master # switches the configurations around a bit, so it's important # that we specify the configs for absolutely everything, every # time. - Certificate.cache_class = nil - CertificateRequest.cache_class = nil - CertificateRevocationList.cache_class = nil + Certificate.indirection.cache_class = nil + CertificateRequest.indirection.cache_class = nil + CertificateRevocationList.indirection.cache_class = nil end end @@ -94,7 +94,7 @@ class Puppet::SSL::Host # Remove all traces of a given host def self.destroy(name) - [Key, Certificate, CertificateRequest].collect { |part| part.destroy(name) }.any? { |x| x } + [Key, Certificate, CertificateRequest].collect { |part| part.indirection.destroy(name) }.any? { |x| x } end # Search for more than one host, optionally only specifying @@ -106,7 +106,7 @@ class Puppet::SSL::Host # Collect the results from each class, flatten them, collect all of the names, make the name list unique, # then create a Host instance for each one. - classlist.collect { |klass| klass.search }.flatten.collect { |r| r.name }.uniq.collect do |name| + classlist.collect { |klass| klass.indirection.search }.flatten.collect { |r| r.name }.uniq.collect do |name| new(name) end end @@ -117,7 +117,7 @@ class Puppet::SSL::Host end def key - @key ||= Key.find(name) + @key ||= Key.indirection.find(name) end # This is the private key; we can create it from scratch @@ -126,7 +126,7 @@ class Puppet::SSL::Host @key = Key.new(name) @key.generate begin - @key.save + Key.indirection.save(@key) rescue @key = nil raise @@ -135,7 +135,7 @@ class Puppet::SSL::Host end def certificate_request - @certificate_request ||= CertificateRequest.find(name) + @certificate_request ||= CertificateRequest.indirection.find(name) end # Our certificate request requires the key but that's all. @@ -144,7 +144,7 @@ class Puppet::SSL::Host @certificate_request = CertificateRequest.new(name) @certificate_request.generate(key.content) begin - @certificate_request.save + CertificateRequest.indirection.save(@certificate_request) rescue @certificate_request = nil raise @@ -159,8 +159,8 @@ class Puppet::SSL::Host # get the CA cert first, since it's required for the normal cert # to be of any use. - return nil unless Certificate.find("ca") unless ca? - return nil unless @certificate = Certificate.find(name) + return nil unless Certificate.indirection.find("ca") unless ca? + return nil unless @certificate = Certificate.indirection.find(name) unless certificate_matches_key? raise Puppet::Error, "Retrieved certificate does not match private key; please remove certificate from server and regenerate it with the current key" @@ -212,7 +212,7 @@ class Puppet::SSL::Host @ssl_store.add_file(Puppet[:localcacert]) # If there's a CRL, add it to our store. - if crl = Puppet::SSL::CertificateRevocationList.find(CA_NAME) + if crl = Puppet::SSL::CertificateRevocationList.indirection.find(CA_NAME) @ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation] @ssl_store.add_crl(crl.content) end diff --git a/lib/puppet/ssl/inventory.rb b/lib/puppet/ssl/inventory.rb index b2b402a53..e094da100 100644 --- a/lib/puppet/ssl/inventory.rb +++ b/lib/puppet/ssl/inventory.rb @@ -36,7 +36,7 @@ class Puppet::SSL::Inventory f.print "# Inventory of signed certificates\n# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n" end - Puppet::SSL::Certificate.search("*").each { |cert| add(cert) } + Puppet::SSL::Certificate.indirection.search("*").each { |cert| add(cert) } end # Find the serial number for a given certificate. diff --git a/lib/puppet/sslcertificates/monkey_patch.rb b/lib/puppet/sslcertificates/monkey_patch.rb deleted file mode 100644 index 663b944c1..000000000 --- a/lib/puppet/sslcertificates/monkey_patch.rb +++ /dev/null @@ -1,6 +0,0 @@ -# This is the file that we use to add indirection to all the SSL Certificate classes. - -require 'puppet/indirector' - -OpenSSL::PKey::RSA.extend Puppet::Indirector -OpenSSL::PKey::RSA.indirects :ssl_rsa, :terminus_class => :file diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index dcd9aad0a..4c0ea9ac5 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -298,7 +298,7 @@ class Puppet::Transaction if Puppet[:report] begin - report.save + Puppet::Transaction::Report.indirection.save(report) rescue => detail Puppet.err "Reporting failed: #{detail}" end 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/type/file.rb b/lib/puppet/type/file.rb index f35a26408..0a07b6798 100644 --- a/lib/puppet/type/file.rb +++ b/lib/puppet/type/file.rb @@ -587,7 +587,7 @@ Puppet::Type.newtype(:file) do def perform_recursion(path) - Puppet::FileServing::Metadata.search( + Puppet::FileServing::Metadata.indirection.search( path, :links => self[:links], diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 7d03de2b0..19dabbdc3 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -98,7 +98,7 @@ module Puppet 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) + unless tmp = Puppet::FileServing::Content.indirection.find(metadata.source) fail "Could not find any content at %s" % metadata.source end tmp.content @@ -148,7 +148,7 @@ module Puppet result = nil value.each do |source| begin - if data = Puppet::FileServing::Metadata.find(source) + if data = Puppet::FileServing::Metadata.indirection.find(source) result = data result.source = source break diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb index 8ab750459..1af74d886 100755 --- a/lib/puppet/type/host.rb +++ b/lib/puppet/type/host.rb @@ -5,11 +5,11 @@ 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 @@ -26,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 @@ -61,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." diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb index d048c90f1..e8c6b3290 100755 --- a/lib/puppet/type/mount.rb +++ b/lib/puppet/type/mount.rb @@ -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) diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index c00f02789..786a50448 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -100,6 +100,8 @@ module Puppet 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 diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb index b7a1b8a8d..59a1a12f8 100755 --- a/lib/puppet/type/sshkey.rb +++ b/lib/puppet/type/sshkey.rb @@ -41,7 +41,7 @@ module Puppet raise Puppet::Error, "Aliases cannot include whitespace" end if value =~ /,/ - raise Puppet::Error, "Aliases cannot include whitespace" + raise Puppet::Error, "Aliases must be provided as an array, not a comma-separated list" end end end @@ -50,6 +50,11 @@ module Puppet desc "The host name that the key is associated with." isnamevar + + validate do |value| + raise Puppet::Error, "Resourcename cannot include whitespaces" if value =~ /\s/ + raise Puppet::Error, "No comma in resourcename allowed. If you want to specify aliases use the host_aliases property" if value.include?(',') + end end newproperty(:target) do diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb index 65cc077cf..93a7e96cf 100755 --- a/lib/puppet/type/tidy.rb +++ b/lib/puppet/type/tidy.rb @@ -141,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/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 8f55e7b44..7fdc6951f 100644 --- a/lib/puppet/util/metric.rb +++ b/lib/puppet/util/metric.rb @@ -122,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 @@ -132,7 +132,7 @@ 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 @@ -173,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 6b5af8350..1c35ae523 100644 --- a/lib/puppet/util/monkey_patches.rb +++ b/lib/puppet/util/monkey_patches.rb @@ -48,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/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb index f9becede1..ce34442ab 100644 --- a/lib/puppet/util/rdoc/parser.rb +++ b/lib/puppet/util/rdoc/parser.rb @@ -17,7 +17,7 @@ class Parser SITE = "__site__" - attr_accessor :ast, :input_file_name, :top_level + attr_accessor :input_file_name, :top_level # parser registration into RDoc parse_files_matching(/\.(rb|pp)$/) @@ -33,15 +33,18 @@ class Parser # main entry point def scan - env = Puppet::Node::Environment.new - unless env.known_resource_types.watching_file?(@input_file_name) + 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(env) + @parser = Puppet::Parser::Parser.new(environment) @parser.file = @input_file_name - @ast = @parser.parse + @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 - scan_top_level(@top_level) end @top_level end @@ -204,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.parameters.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 @@ -337,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? @@ -350,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/zaml.rb b/lib/puppet/util/zaml.rb index 9fda5ae3b..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 diff --git a/spec/integration/configurer_spec.rb b/spec/integration/configurer_spec.rb index 9a8b66fe4..71b9652e8 100755 --- a/spec/integration/configurer_spec.rb +++ b/spec/integration/configurer_spec.rb @@ -5,6 +5,8 @@ require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/configurer' describe Puppet::Configurer do + include PuppetSpec::Files + describe "when downloading plugins" do it "should use the :pluginsignore setting, split on whitespace, for ignoring remote files" do resource = Puppet::Type.type(:notify).new :name => "yay" @@ -17,19 +19,50 @@ describe Puppet::Configurer do end describe "when running" do - it "should send a transaction report with valid data" do - catalog = Puppet::Resource::Catalog.new - catalog.add_resource(Puppet::Type.type(:notify).new(:title => "testing")) + before(:each) do + @catalog = Puppet::Resource::Catalog.new + @catalog.add_resource(Puppet::Type.type(:notify).new(:title => "testing")) - configurer = Puppet::Configurer.new + # Make sure we don't try to persist the local state after the transaction ran, + # because it will fail during test (the state file is in an not existing directory) + # and we need the transaction to be successful to be able to produce a summary report + @catalog.host_config = false + + @configurer = Puppet::Configurer.new + end + + it "should send a transaction report with valid data" do - Puppet::Transaction::Report.indirection.expects(:save).with do |x, report| + @configurer.stubs(:save_last_run_summary) + Puppet::Transaction::Report.indirection.expects(:save).with do |report, x| report.time.class == Time and report.logs.length > 0 end Puppet[:report] = true - configurer.run :catalog => catalog + @configurer.run :catalog => @catalog + end + + it "should save a correct last run summary" do + report = Puppet::Transaction::Report.new + report.stubs(:save) + + Puppet[:lastrunfile] = tmpfile("lastrunfile") + Puppet[:report] = true + + @configurer.run :catalog => @catalog, :report => report + + summary = nil + File.open(Puppet[:lastrunfile], "r") do |fd| + summary = YAML.load(fd.read) + end + + summary.should be_a(Hash) + %w{time changes events resources}.each do |key| + summary.should be_key(key) + end + summary["time"].should be_key("notify") + summary["time"]["last_run"].should >= Time.now.tv_sec end end end diff --git a/spec/integration/defaults_spec.rb b/spec/integration/defaults_spec.rb index 1f90c7cbc..051f3e528 100755 --- a/spec/integration/defaults_spec.rb +++ b/spec/integration/defaults_spec.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/defaults' +require 'puppet/rails' describe "Puppet defaults" do include Puppet::Util::Execution @@ -115,31 +116,31 @@ describe "Puppet defaults" do describe "when enabling storeconfigs" do before do - Puppet::Resource::Catalog.stubs(:cache_class=) - Puppet::Node::Facts.stubs(:cache_class=) - Puppet::Node.stubs(:cache_class=) + Puppet::Resource::Catalog.indirection.stubs(:cache_class=) + Puppet::Node::Facts.indirection.stubs(:cache_class=) + Puppet::Node.indirection.stubs(:cache_class=) Puppet.features.stubs(:rails?).returns true end it "should set the Catalog cache class to :active_record" do - Puppet::Resource::Catalog.expects(:cache_class=).with(:active_record) + Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end it "should not set the Catalog cache class to :active_record if asynchronous storeconfigs is enabled" do - Puppet::Resource::Catalog.expects(:cache_class=).with(:active_record).never + Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:active_record).never Puppet.settings.expects(:value).with(:async_storeconfigs).returns true Puppet.settings[:storeconfigs] = true end it "should set the Facts cache class to :active_record" do - Puppet::Node::Facts.expects(:cache_class=).with(:active_record) + Puppet::Node::Facts.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end it "should set the Node cache class to :active_record" do - Puppet::Node.expects(:cache_class=).with(:active_record) + Puppet::Node.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end @@ -151,9 +152,9 @@ describe "Puppet defaults" do describe "when enabling asynchronous storeconfigs" do before do - Puppet::Resource::Catalog.stubs(:cache_class=) - Puppet::Node::Facts.stubs(:cache_class=) - Puppet::Node.stubs(:cache_class=) + Puppet::Resource::Catalog.indirection.stubs(:cache_class=) + Puppet::Node::Facts.indirection.stubs(:cache_class=) + Puppet::Node.indirection.stubs(:cache_class=) Puppet.features.stubs(:rails?).returns true end @@ -163,26 +164,26 @@ describe "Puppet defaults" do end it "should set the Catalog cache class to :queue" do - Puppet::Resource::Catalog.expects(:cache_class=).with(:queue) + Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:queue) Puppet.settings[:async_storeconfigs] = true end it "should set the Facts cache class to :active_record" do - Puppet::Node::Facts.expects(:cache_class=).with(:active_record) + Puppet::Node::Facts.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end it "should set the Node cache class to :active_record" do - Puppet::Node.expects(:cache_class=).with(:active_record) + Puppet::Node.indirection.expects(:cache_class=).with(:active_record) Puppet.settings[:storeconfigs] = true end end describe "when enabling thin storeconfigs" do before do - Puppet::Resource::Catalog.stubs(:cache_class=) - Puppet::Node::Facts.stubs(:cache_class=) - Puppet::Node.stubs(:cache_class=) + Puppet::Resource::Catalog.indirection.stubs(:cache_class=) + Puppet::Node::Facts.indirection.stubs(:cache_class=) + Puppet::Node.indirection.stubs(:cache_class=) Puppet.features.stubs(:rails?).returns true end diff --git a/spec/integration/indirector/bucket_file/rest_spec.rb b/spec/integration/indirector/bucket_file/rest_spec.rb deleted file mode 100644 index acfc0594b..000000000 --- a/spec/integration/indirector/bucket_file/rest_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/file_bucket/file' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Filebucket REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:group] = Process.gid - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - ca.generate("foo.madstop.com") unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @host = Puppet::SSL::Host.new(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :file_bucket_file ] } - retries = 0 - begin - @server = Puppet::Network::Server.new(@params) - @server.listen - rescue Errno::EADDRINUSE => e - sleep 0.1 - puts "Port 34343 is in use; waiting for it to be free" if retries == 50 - retry if (retries += 1) < 100 - pending "Can't run too many simultaneous tests" - end - - @old_terminus = Puppet::FileBucket::File.indirection.terminus_class - Puppet::FileBucket::File.terminus_class = :rest - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @file_bucket_file = stub_everything 'file_bucket_file' - @mock_model = stub('faked model', :name => "file_bucket_file", :convert_from => @file_bucket_file) - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - Puppet::FileBucket::File.terminus_class = @old_terminus - end - - it "should be able save a file to the remote filebucket" do - @file_bucket_file.expects(:save) - - file_bucket_file = Puppet::FileBucket::File.new("pouet") - file_bucket_file.save - end -end diff --git a/spec/integration/indirector/catalog/compiler_spec.rb b/spec/integration/indirector/catalog/compiler_spec.rb index ede502e3c..dcb7eb425 100755 --- a/spec/integration/indirector/catalog/compiler_spec.rb +++ b/spec/integration/indirector/catalog/compiler_spec.rb @@ -42,7 +42,7 @@ describe Puppet::Resource::Catalog::Compiler do Puppet::Resource::Catalog.indirection.terminus.stubs(:node_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:compile).returns(@catalog) - Puppet::Resource::Catalog.find(request).resource_refs.should == [ @two.ref ] + Puppet::Resource::Catalog.indirection.find(request).resource_refs.should == [ @two.ref ] end it "should not filter out exported resources when finding a catalog" do @@ -52,7 +52,7 @@ describe Puppet::Resource::Catalog::Compiler do Puppet::Resource::Catalog.indirection.terminus.stubs(:node_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:compile).returns(@catalog) - Puppet::Resource::Catalog.find(request).resource_refs.sort.should == [ @one.ref, @two.ref ] + Puppet::Resource::Catalog.indirection.find(request).resource_refs.sort.should == [ @one.ref, @two.ref ] end it "should filter out virtual exported resources when finding a catalog" do @@ -63,6 +63,6 @@ describe Puppet::Resource::Catalog::Compiler do Puppet::Resource::Catalog.indirection.terminus.stubs(:node_from_request) Puppet::Resource::Catalog.indirection.terminus.stubs(:compile).returns(@catalog) - Puppet::Resource::Catalog.find(request).resource_refs.should == [ @two.ref ] + Puppet::Resource::Catalog.indirection.find(request).resource_refs.should == [ @two.ref ] end end diff --git a/spec/integration/indirector/certificate/rest_spec.rb b/spec/integration/indirector/certificate/rest_spec.rb deleted file mode 100755 index 58aa96c48..000000000 --- a/spec/integration/indirector/certificate/rest_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/ssl/certificate' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Certificate REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:group] = Process.gid - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - ca.generate("foo.madstop.com") unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @host = Puppet::SSL::Host.new(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :certificate ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # Then switch to a remote CA, so that we go through REST. - Puppet::SSL::Host.ca_location = :remote - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "certificate") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization).returns(true) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - end - - it "should be able to retrieve a remote certificate" do - @mock_model.expects(:find).returns @host.certificate - result = Puppet::SSL::Certificate.find('bar') - - # There's no good '==' method on certs. - result.content.to_s.should == @host.certificate.content.to_s - result.name.should == "bar" - end -end diff --git a/spec/integration/indirector/certificate_request/rest_spec.rb b/spec/integration/indirector/certificate_request/rest_spec.rb deleted file mode 100755 index c718b78ab..000000000 --- a/spec/integration/indirector/certificate_request/rest_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/ssl/certificate_request' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Certificate Request REST Terminus" do - before do - Puppet::Util::Cacher.expire - - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:group] = Process.gid - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - # Create the CSR and write it to disk - @host = Puppet::SSL::Host.new("foo.madstop.com") - @host.generate_certificate_request - - # Now remove the cached csr - Puppet::SSL::Host.ca_location = :none - Puppet::SSL::Host.destroy("foo.madstop.com") - - @params = { :port => 34343, :handlers => [ :certificate_request ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # Then switch to a remote CA, so that we go through REST. - Puppet::SSL::Host.ca_location = :remote - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "certificate request") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization).returns(true) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - end - - it "should be able to save a certificate request to the CA" do - key = Puppet::SSL::Key.new("bar.madstop.com") - key.generate - - csr = Puppet::SSL::CertificateRequest.new("bar.madstop.com") - csr.generate(key.content) - - server_csr = mock 'csr' - server_csr.expects(:save) - @mock_model.expects(:convert_from).with("s", csr.content.to_s).returns server_csr - - csr.save - end - - it "should be able to retrieve a remote certificate request" do - # We're finding the cached value :/ - @mock_model.expects(:find).returns @host.certificate_request - result = Puppet::SSL::CertificateRequest.find('foo.madstop.com') - - # There's no good '==' method on certs. - result.content.to_s.should == @host.certificate_request.content.to_s - result.name.should == @host.certificate_request.name - end -end diff --git a/spec/integration/indirector/certificate_revocation_list/rest_spec.rb b/spec/integration/indirector/certificate_revocation_list/rest_spec.rb deleted file mode 100755 index 74e3f90a0..000000000 --- a/spec/integration/indirector/certificate_revocation_list/rest_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/ssl/certificate' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Certificate REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:group] = Process.gid - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :certificate_revocation_list ] } - retries = 0 - begin - @server = Puppet::Network::Server.new(@params) - @server.listen - rescue Errno::EADDRINUSE => e - sleep 0.1 - puts "Port 34343 is in use; waiting for it to be free" if retries == 50 - retry if (retries += 1) < 100 - pending "Can't run too many simultaneous tests" - end - - # And make sure we've generated the CRL - @crl = ca.crl - - # Now remove the cached crl - Puppet::SSL::Host.ca_location = :none - Puppet::SSL::CertificateRevocationList.destroy(Puppet::SSL::CA_NAME) - - # This is necessary so that we create the SSL store before we start - # using REST. This is necessary to prevent an infinite loop, - # which only occurs during testing. - Puppet::Network::HttpPool.ssl_host.ssl_store - - # Then switch to a remote CA, so that we go through REST. - Puppet::SSL::Host.ca_location = :remote - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'find', which would cause an immediate - # return. - @mock_model = stub('faked model', :name => "certificate") - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization).returns(true) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - end - - it "should be able to retrieve a remote CRL" do - @mock_model.expects(:find).returns @crl - result = Puppet::SSL::CertificateRevocationList.find('bar') - - # There's no good '==' method on certs. - result.content.to_s.should == @crl.content.to_s - end -end diff --git a/spec/integration/indirector/file_content/file_server_spec.rb b/spec/integration/indirector/file_content/file_server_spec.rb index 5de7f1de0..2992c40f2 100755 --- a/spec/integration/indirector/file_content/file_server_spec.rb +++ b/spec/integration/indirector/file_content/file_server_spec.rb @@ -34,7 +34,7 @@ describe Puppet::Indirector::FileContent::FileServer, " when finding files" do env = Puppet::Node::Environment.new("foo") env.stubs(:modulepath).returns [path] - result = Puppet::FileServing::Content.search("plugins", :environment => "foo", :recurse => true) + result = Puppet::FileServing::Content.indirection.search("plugins", :environment => "foo", :recurse => true) result.should_not be_nil result.length.should == 2 @@ -54,7 +54,7 @@ describe Puppet::Indirector::FileContent::FileServer, " when finding files" do Puppet.settings[:modulepath] = path - result = Puppet::FileServing::Content.find("modules/mymod/myfile") + result = Puppet::FileServing::Content.indirection.find("modules/mymod/myfile") result.should_not be_nil result.should be_instance_of(Puppet::FileServing::Content) @@ -85,7 +85,7 @@ describe Puppet::Indirector::FileContent::FileServer, " when finding files" do path = File.join(@path, "myfile") - result = Puppet::FileServing::Content.find("one/myfile", :environment => "foo", :node => "mynode") + result = Puppet::FileServing::Content.indirection.find("one/myfile", :environment => "foo", :node => "mynode") result.should_not be_nil result.should be_instance_of(Puppet::FileServing::Content) diff --git a/spec/integration/indirector/node/ldap_spec.rb b/spec/integration/indirector/node/ldap_spec.rb index e4c0867ad..b13f3c033 100755 --- a/spec/integration/indirector/node/ldap_spec.rb +++ b/spec/integration/indirector/node/ldap_spec.rb @@ -10,6 +10,6 @@ describe Puppet::Node::Ldap do Puppet::Node.indirection.stubs(:terminus).returns ldap ldap.expects(:ldapsearch).with("(&(objectclass=puppetClient)(puppetclass=foo))") - Puppet::Node.search "eh", :class => "foo" + Puppet::Node.indirection.search "eh", :class => "foo" end end diff --git a/spec/integration/indirector/report/rest_spec.rb b/spec/integration/indirector/report/rest_spec.rb deleted file mode 100644 index fdc218975..000000000 --- a/spec/integration/indirector/report/rest_spec.rb +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env ruby - -Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } - -require 'puppet/transaction/report' -require 'puppet/network/server' -require 'puppet/network/http/webrick/rest' - -describe "Report REST Terminus" do - before do - Puppet[:masterport] = 34343 - Puppet[:server] = "localhost" - - # Get a safe temporary file - @tmpfile = Tempfile.new("webrick_integration_testing") - @dir = @tmpfile.path + "_dir" - - Puppet.settings[:confdir] = @dir - Puppet.settings[:vardir] = @dir - Puppet.settings[:group] = Process.gid - Puppet.settings[:server] = "127.0.0.1" - Puppet.settings[:masterport] = "34343" - - Puppet::Util::Cacher.expire - - Puppet[:servertype] = 'webrick' - Puppet[:server] = '127.0.0.1' - Puppet[:certname] = '127.0.0.1' - - # Generate the certificate with a local CA - Puppet::SSL::Host.ca_location = :local - ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) - ca.generate("foo.madstop.com") unless Puppet::SSL::Certificate.find(Puppet[:certname]) - - @host = Puppet::SSL::Host.new(Puppet[:certname]) - - @params = { :port => 34343, :handlers => [ :report ] } - @server = Puppet::Network::Server.new(@params) - @server.listen - - # Let's use REST for our reports :-) - @old_terminus = Puppet::Transaction::Report.indirection.terminus_class - Puppet::Transaction::Report.terminus_class = :rest - - # LAK:NOTE We need to have a fake model here so that our indirected methods get - # passed through REST; otherwise we'd be stubbing 'save', which would cause an immediate - # return. - @report = stub_everything 'report' - @mock_model = stub_everything 'faked model', :name => "report", :convert_from => @report - Puppet::Indirector::Request.any_instance.stubs(:model).returns(@mock_model) - - Puppet::Network::HTTP::WEBrickREST.any_instance.stubs(:check_authorization) - end - - after do - Puppet::Network::HttpPool.expire - Puppet::SSL::Host.ca_location = :none - Puppet.settings.clear - @server.unlisten - Puppet::Transaction::Report.terminus_class = @old_terminus - end - - it "should be able to send a report to the server" do - @report.expects(:save) - - report = Puppet::Transaction::Report.new - - resourcemetrics = { - :total => 12, - :out_of_sync => 20, - :applied => 45, - :skipped => 1, - :restarted => 23, - :failed_restarts => 1, - :scheduled => 10 - } - report.add_metric(:resources, resourcemetrics) - - timemetrics = { - :resource1 => 10, - :resource2 => 50, - :resource3 => 40, - :resource4 => 20, - } - report.add_metric(:times, timemetrics) - - - report.add_metric( - :changes, - - :total => 20 - ) - - report.save - end -end diff --git a/spec/integration/network/server/webrick_spec.rb b/spec/integration/network/server/webrick_spec.rb index 2b14dfb37..963e27940 100755 --- a/spec/integration/network/server/webrick_spec.rb +++ b/spec/integration/network/server/webrick_spec.rb @@ -23,7 +23,7 @@ describe Puppet::Network::Server do Puppet::SSL::Host.ca_location = :local ca = Puppet::SSL::CertificateAuthority.new - ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.find(Puppet[:certname]) + ca.generate(Puppet[:certname]) unless Puppet::SSL::Certificate.indirection.find(Puppet[:certname]) end after do @@ -32,6 +32,7 @@ describe Puppet::Network::Server do system("rm -rf #{@dir}") + Puppet::SSL::Host.ca_location = :none Puppet::Util::Cacher.expire end diff --git a/spec/integration/node/facts_spec.rb b/spec/integration/node/facts_spec.rb index 4cc2f4c1f..a555b2044 100755 --- a/spec/integration/node/facts_spec.rb +++ b/spec/integration/node/facts_spec.rb @@ -16,10 +16,10 @@ describe Puppet::Node::Facts do terminus = Puppet::Node::Facts.indirection.terminus(:yaml) terminus.stubs :save - Puppet::Node.expects(:expire).with("me") + Puppet::Node.indirection.expects(:expire).with("me") facts = Puppet::Node::Facts.new("me") - facts.save + Puppet::Node::Facts.indirection.save(facts) end it "should be able to delegate to the :yaml terminus" do @@ -31,7 +31,7 @@ describe Puppet::Node::Facts do terminus.expects(:path).with("me").returns "/my/yaml/file" FileTest.expects(:exist?).with("/my/yaml/file").returns false - Puppet::Node::Facts.find("me").should be_nil + Puppet::Node::Facts.indirection.find("me").should be_nil end it "should be able to delegate to the :facter terminus" do @@ -41,7 +41,7 @@ describe Puppet::Node::Facts do facts = Puppet::Node::Facts.new("me") Puppet::Node::Facts.expects(:new).with("me", "facter_hash").returns facts - Puppet::Node::Facts.find("me").should equal(facts) + Puppet::Node::Facts.indirection.find("me").should equal(facts) end end end diff --git a/spec/integration/node_spec.rb b/spec/integration/node_spec.rb index c635e7f32..911a423a0 100755 --- a/spec/integration/node_spec.rb +++ b/spec/integration/node_spec.rb @@ -24,7 +24,7 @@ describe Puppet::Node do terminus.expects(:translate).with(@name, "myresults").returns "translated_results" terminus.expects(:create_node).with(@name, "translated_results").returns @node - Puppet::Node.find(@name).should equal(@node) + Puppet::Node.indirection.find(@name).should equal(@node) end it "should be able to use the yaml terminus" do @@ -36,7 +36,7 @@ describe Puppet::Node do terminus.expects(:path).with(@name).returns "/my/yaml/file" FileTest.expects(:exist?).with("/my/yaml/file").returns false - Puppet::Node.find(@name).should be_nil + Puppet::Node.indirection.find(@name).should be_nil end it "should have an ldap terminus" do @@ -51,7 +51,7 @@ describe Puppet::Node do Puppet::Node.expects(:new).with(@name).returns @node - Puppet::Node.find(@name).should equal(@node) + Puppet::Node.indirection.find(@name).should equal(@node) end describe "and using the memory terminus" do @@ -64,29 +64,29 @@ describe Puppet::Node do end it "should find no nodes by default" do - Puppet::Node.find(@name).should be_nil + Puppet::Node.indirection.find(@name).should be_nil end it "should be able to find nodes that were previously saved" do - @node.save - Puppet::Node.find(@name).should equal(@node) + Puppet::Node.indirection.save(@node) + Puppet::Node.indirection.find(@name).should equal(@node) end it "should replace existing saved nodes when a new node with the same name is saved" do - @node.save + Puppet::Node.indirection.save(@node) two = Puppet::Node.new(@name) - two.save - Puppet::Node.find(@name).should equal(two) + Puppet::Node.indirection.save(two) + Puppet::Node.indirection.find(@name).should equal(two) end it "should be able to remove previously saved nodes" do - @node.save - Puppet::Node.destroy(@node.name) - Puppet::Node.find(@name).should be_nil + Puppet::Node.indirection.save(@node) + Puppet::Node.indirection.destroy(@node.name) + Puppet::Node.indirection.find(@name).should be_nil end it "should fail when asked to destroy a node that does not exist" do - proc { Puppet::Node.destroy(@node) }.should raise_error(ArgumentError) + proc { Puppet::Node.indirection.destroy(@node) }.should raise_error(ArgumentError) end end end diff --git a/spec/integration/parser/collector_spec.rb b/spec/integration/parser/collector_spec.rb index 73273c909..b1cfc51c7 100755 --- a/spec/integration/parser/collector_spec.rb +++ b/spec/integration/parser/collector_spec.rb @@ -17,7 +17,7 @@ describe Puppet::Parser::Collector do def query(text) code = "File <| #{text} |>" parser = Puppet::Parser::Parser.new(@scope.compiler) - parser.parse(code).hostclass("").code[0].query + return parser.parse(code).code[0].query end {true => [%{title == "/tmp/testing"}, %{(title == "/tmp/testing")}, %{group == bin}, diff --git a/spec/integration/parser/compiler_spec.rb b/spec/integration/parser/compiler_spec.rb index f80221e3d..f731692b3 100755 --- a/spec/integration/parser/compiler_spec.rb +++ b/spec/integration/parser/compiler_spec.rb @@ -90,4 +90,45 @@ describe Puppet::Parser::Compiler do notify_resource[:require].title.should == "Experiment::Baz" end end + + it "should recompute the version after input files are re-parsed" do + Puppet[:code] = 'class foo { }' + Time.stubs(:now).returns(1) + node = Puppet::Node.new('mynode') + Puppet::Parser::Compiler.compile(node).version.should == 1 + Time.stubs(:now).returns(2) + Puppet::Parser::Compiler.compile(node).version.should == 1 # no change because files didn't change + Puppet::Resource::TypeCollection.any_instance.stubs(:stale?).returns(true).then.returns(false) # pretend change + Puppet::Parser::Compiler.compile(node).version.should == 2 + end + + ['class', 'define', 'node'].each do |thing| + it "should not allow #{thing} inside evaluated conditional constructs" do + Puppet[:code] = <<-PP + if true { + #{thing} foo { + } + notify { decoy: } + } + PP + + begin + Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) + raise "compilation should have raised Puppet::Error" + rescue Puppet::Error => e + e.message.should =~ /at line 2/ + end + end + end + + it "should not allow classes inside unevaluated conditional constructs" do + Puppet[:code] = <<-PP + if false { + class foo { + } + } + PP + + lambda { Puppet::Parser::Compiler.compile(Puppet::Node.new("mynode")) }.should raise_error(Puppet::Error) + end end diff --git a/spec/integration/parser/parser_spec.rb b/spec/integration/parser/parser_spec.rb index 7b85bcacb..0d9aa51e1 100755 --- a/spec/integration/parser/parser_spec.rb +++ b/spec/integration/parser/parser_spec.rb @@ -11,7 +11,7 @@ describe Puppet::Parser::Parser do end def result_instance - @result.hostclass("").code[0] + @result.code[0] end def matches?(string) @@ -44,7 +44,7 @@ describe Puppet::Parser::Parser do end def result_instance - @result.hostclass("").code[0] + @result.code[0] end def matches?(string) @@ -85,7 +85,9 @@ describe Puppet::Parser::Parser do class test {} """) - ast.hostclass("test").doc.should == "comment\n" + ast.code[0].should be_a(Puppet::Parser::AST::Hostclass) + ast.code[0].name.should == 'test' + ast.code[0].instantiate('')[0].doc.should == "comment\n" end end diff --git a/spec/integration/resource/catalog_spec.rb b/spec/integration/resource/catalog_spec.rb index 0a3d47a80..206fe909c 100755 --- a/spec/integration/resource/catalog_spec.rb +++ b/spec/integration/resource/catalog_spec.rb @@ -30,7 +30,7 @@ describe Puppet::Resource::Catalog do terminus.expects(:path).with("me").returns "/my/yaml/file" FileTest.expects(:exist?).with("/my/yaml/file").returns false - Puppet::Resource::Catalog.find("me").should be_nil + Puppet::Resource::Catalog.indirection.find("me").should be_nil end it "should be able to delegate to the :compiler terminus" do @@ -42,10 +42,10 @@ describe Puppet::Resource::Catalog do node = mock 'node' node.stub_everything - Puppet::Node.expects(:find).returns(node) + Puppet::Node.indirection.expects(:find).returns(node) compiler.expects(:compile).with(node).returns nil - Puppet::Resource::Catalog.find("me").should be_nil + Puppet::Resource::Catalog.indirection.find("me").should be_nil end it "should pass provided node information directly to the terminus" do @@ -55,7 +55,7 @@ describe Puppet::Resource::Catalog do node = mock 'node' terminus.expects(:find).with { |request| request.options[:use_node] == node } - Puppet::Resource::Catalog.find("me", :use_node => node) + Puppet::Resource::Catalog.indirection.find("me", :use_node => node) end end end diff --git a/spec/integration/ssl/certificate_authority_spec.rb b/spec/integration/ssl/certificate_authority_spec.rb index 67ff6f215..622f7ed01 100755 --- a/spec/integration/ssl/certificate_authority_spec.rb +++ b/spec/integration/ssl/certificate_authority_spec.rb @@ -47,7 +47,7 @@ describe Puppet::SSL::CertificateAuthority do it "should be able to generate a new host certificate" do @ca.generate("newhost") - Puppet::SSL::Certificate.find("newhost").should be_instance_of(Puppet::SSL::Certificate) + Puppet::SSL::Certificate.indirection.find("newhost").should be_instance_of(Puppet::SSL::Certificate) end it "should be able to revoke a host certificate" do @@ -94,7 +94,7 @@ describe Puppet::SSL::CertificateAuthority do it "should save the signed certificate" do @ca.sign("luke.madstop.com") - Puppet::SSL::Certificate.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate) + Puppet::SSL::Certificate.indirection.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate) end it "should be able to sign multiple certificates" do @@ -107,15 +107,15 @@ describe Puppet::SSL::CertificateAuthority do @ca.sign("luke.madstop.com") @ca.sign("other.madstop.com") - Puppet::SSL::Certificate.find("other.madstop.com").should be_instance_of(Puppet::SSL::Certificate) - Puppet::SSL::Certificate.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate) + Puppet::SSL::Certificate.indirection.find("other.madstop.com").should be_instance_of(Puppet::SSL::Certificate) + Puppet::SSL::Certificate.indirection.find("luke.madstop.com").should be_instance_of(Puppet::SSL::Certificate) end it "should save the signed certificate to the :signeddir" do @ca.sign("luke.madstop.com") client_cert = File.join(Puppet[:signeddir], "luke.madstop.com.pem") - File.read(client_cert).should == Puppet::SSL::Certificate.find("luke.madstop.com").content.to_s + File.read(client_cert).should == Puppet::SSL::Certificate.indirection.find("luke.madstop.com").content.to_s end it "should save valid certificates" do diff --git a/spec/integration/ssl/certificate_request_spec.rb b/spec/integration/ssl/certificate_request_spec.rb index 8426b9dc5..d92346bb1 100755 --- a/spec/integration/ssl/certificate_request_spec.rb +++ b/spec/integration/ssl/certificate_request_spec.rb @@ -43,20 +43,20 @@ describe Puppet::SSL::CertificateRequest do end it "should be able to save CSRs" do - @csr.save + Puppet::SSL::CertificateRequest.indirection.save(@csr) end it "should be able to find saved certificate requests via the Indirector" do @csr.generate(@key) - @csr.save + Puppet::SSL::CertificateRequest.indirection.save(@csr) - Puppet::SSL::CertificateRequest.find("luke.madstop.com").should be_instance_of(Puppet::SSL::CertificateRequest) + Puppet::SSL::CertificateRequest.indirection.find("luke.madstop.com").should be_instance_of(Puppet::SSL::CertificateRequest) end it "should save the completely CSR when saving" do @csr.generate(@key) - @csr.save + Puppet::SSL::CertificateRequest.indirection.save(@csr) - Puppet::SSL::CertificateRequest.find("luke.madstop.com").content.to_s.should == @csr.content.to_s + Puppet::SSL::CertificateRequest.indirection.find("luke.madstop.com").content.to_s.should == @csr.content.to_s end end diff --git a/spec/integration/ssl/host_spec.rb b/spec/integration/ssl/host_spec.rb index 05862dfc4..c488eb229 100755 --- a/spec/integration/ssl/host_spec.rb +++ b/spec/integration/ssl/host_spec.rb @@ -45,7 +45,7 @@ describe Puppet::SSL::Host do it "should save the key such that the Indirector can find it" do @host.generate_key - Puppet::SSL::Key.find(@host.name).content.to_s.should == @host.key.to_s + Puppet::SSL::Key.indirection.find(@host.name).content.to_s.should == @host.key.to_s end it "should save the private key into the :privatekeydir" do @@ -62,7 +62,7 @@ describe Puppet::SSL::Host do it "should save the certificate request such that the Indirector can find it" do @host.generate_certificate_request - Puppet::SSL::CertificateRequest.find(@host.name).content.to_s.should == @host.certificate_request.to_s + Puppet::SSL::CertificateRequest.indirection.find(@host.name).content.to_s.should == @host.certificate_request.to_s end it "should save the private certificate request into the :privatekeydir" do diff --git a/spec/integration/transaction/report_spec.rb b/spec/integration/transaction/report_spec.rb index eed7acaa9..2afd037c7 100755 --- a/spec/integration/transaction/report_spec.rb +++ b/spec/integration/transaction/report_spec.rb @@ -23,7 +23,7 @@ describe Puppet::Transaction::Report do terminus.expects(:process).with(report) - report.save + Puppet::Transaction::Report.indirection.save(report) end end end diff --git a/spec/shared_behaviours/file_serving.rb b/spec/shared_behaviours/file_serving.rb index 5f5b2b0af..91594452d 100644 --- a/spec/shared_behaviours/file_serving.rb +++ b/spec/shared_behaviours/file_serving.rb @@ -12,7 +12,7 @@ describe "Puppet::FileServing::Files", :shared => true do term = @indirection.terminus(:rest) @indirection.stubs(:terminus).with(:rest).returns term term.expects(:find) - @test_class.find(uri) + @indirection.find(uri) end it "should use the rest terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is not 'puppet' or 'apply'" do @@ -21,7 +21,7 @@ describe "Puppet::FileServing::Files", :shared => true do Puppet.settings.stubs(:value).with(:name).returns("puppetd") Puppet.settings.stubs(:value).with(:modulepath).returns("") @indirection.terminus(:rest).expects(:find) - @test_class.find(uri) + @indirection.find(uri) end it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'puppet'" do @@ -32,7 +32,7 @@ describe "Puppet::FileServing::Files", :shared => true do Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") @indirection.terminus(:file_server).expects(:find) @indirection.terminus(:file_server).stubs(:authorized?).returns(true) - @test_class.find(uri) + @indirection.find(uri) end it "should use the file_server terminus when the 'puppet' URI scheme is used, no host name is present, and the process name is 'apply'" do @@ -43,19 +43,19 @@ describe "Puppet::FileServing::Files", :shared => true do Puppet.settings.stubs(:value).with(:fileserverconfig).returns("/whatever") @indirection.terminus(:file_server).expects(:find) @indirection.terminus(:file_server).stubs(:authorized?).returns(true) - @test_class.find(uri) + @indirection.find(uri) end it "should use the file terminus when the 'file' URI scheme is used" do uri = "file:///fakemod/my/file" @indirection.terminus(:file).expects(:find) - @test_class.find(uri) + @indirection.find(uri) end it "should use the file terminus when a fully qualified path is provided" do uri = "/fakemod/my/file" @indirection.terminus(:file).expects(:find) - @test_class.find(uri) + @indirection.find(uri) end it "should use the configuration to test whether the request is allowed" do @@ -66,6 +66,6 @@ describe "Puppet::FileServing::Files", :shared => true do @indirection.terminus(:file_server).expects(:find) mount.expects(:allowed?).returns(true) - @test_class.find(uri, :node => "foo", :ip => "bar") + @indirection.find(uri, :node => "foo", :ip => "bar") end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ed4e2c2fb..0c4b076f4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -72,7 +72,7 @@ Spec::Runner.configure do |config| Puppet.settings[:bindaddress] = "127.0.0.1" @logs = [] - Puppet::Util::Log.newdestination(@logs) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) end end diff --git a/spec/unit/application/agent_spec.rb b/spec/unit/application/agent_spec.rb index 54726c185..151d85a58 100755 --- a/spec/unit/application/agent_spec.rb +++ b/spec/unit/application/agent_spec.rb @@ -6,6 +6,7 @@ require 'puppet/agent' require 'puppet/application/agent' require 'puppet/network/server' require 'puppet/daemon' +require 'puppet/network/handler' describe Puppet::Application::Agent do before :each do @@ -13,15 +14,16 @@ describe Puppet::Application::Agent do @puppetd.stubs(:puts) @daemon = stub_everything 'daemon' Puppet::Daemon.stubs(:new).returns(@daemon) + Puppet[:daemonize] = false @agent = stub_everything 'agent' Puppet::Agent.stubs(:new).returns(@agent) @puppetd.preinit Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) - Puppet::Node.stubs(:terminus_class=) - Puppet::Node.stubs(:cache_class=) - Puppet::Node::Facts.stubs(:terminus_class=) + Puppet::Node.indirection.stubs(:terminus_class=) + Puppet::Node.indirection.stubs(:cache_class=) + Puppet::Node::Facts.indirection.stubs(:terminus_class=) end it "should operate in agent run_mode" do @@ -175,16 +177,13 @@ describe Puppet::Application::Agent do @puppetd.options.stubs(:[]) Puppet.stubs(:info) FileTest.stubs(:exists?).returns(true) - Puppet.stubs(:[]) - Puppet.stubs(:[]=) - Puppet.stubs(:[]).with(:libdir).returns("/dev/null/lib") - Puppet.settings.stubs(:print_config?) - Puppet.settings.stubs(:print_config) + Puppet[:libdir] = "/dev/null/lib" Puppet::SSL::Host.stubs(:ca_location=) - Puppet::Transaction::Report.stubs(:terminus_class=) - Puppet::Resource::Catalog.stubs(:terminus_class=) - Puppet::Resource::Catalog.stubs(:cache_class=) - Puppet::Node::Facts.stubs(:terminus_class=) + Puppet::Transaction::Report.indirection.stubs(:terminus_class=) + Puppet::Transaction::Report.indirection.stubs(:cache_class=) + Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) + Puppet::Resource::Catalog.indirection.stubs(:cache_class=) + Puppet::Node::Facts.indirection.stubs(:terminus_class=) @host = stub_everything 'host' Puppet::SSL::Host.stubs(:new).returns(@host) Puppet.stubs(:settraps) @@ -192,7 +191,7 @@ describe Puppet::Application::Agent do describe "with --test" do before :each do - Puppet.settings.stubs(:handlearg) + #Puppet.settings.stubs(:handlearg) @puppetd.options.stubs(:[]=) end @@ -207,8 +206,9 @@ describe Puppet::Application::Agent do @puppetd.setup_test end it "should set options[:onetime] to true" do - Puppet.expects(:[]=).with(:onetime,true) + Puppet[:onetime] = false @puppetd.setup_test + Puppet[:onetime].should == true end it "should set options[:detailed_exitcodes] to true" do @puppetd.options.expects(:[]=).with(:detailed_exitcodes,true) @@ -264,7 +264,7 @@ describe Puppet::Application::Agent do it "should print puppet config if asked to in Puppet config" do @puppetd.stubs(:exit) - Puppet.settings.stubs(:print_configs?).returns(true) + Puppet[:configprint] = "pluginsync" Puppet.settings.expects(:print_configs) @@ -272,14 +272,14 @@ describe Puppet::Application::Agent do end it "should exit after printing puppet config if asked to in Puppet config" do - Puppet.settings.stubs(:print_configs?).returns(true) + Puppet[:configprint] = "pluginsync" lambda { @puppetd.setup }.should raise_error(SystemExit) end it "should set a central log destination with --centrallogs" do @puppetd.options.stubs(:[]).with(:centrallogs).returns(true) - Puppet.stubs(:[]).with(:server).returns("puppet.reductivelabs.com") + Puppet[:server] = "puppet.reductivelabs.com" Puppet::Util::Log.stubs(:newdestination).with(:syslog) Puppet::Util::Log.expects(:newdestination).with("puppet.reductivelabs.com") @@ -307,26 +307,34 @@ describe Puppet::Application::Agent do end it "should tell the report handler to use REST" do - Puppet::Transaction::Report.expects(:terminus_class=).with(:rest) + Puppet::Transaction::Report.indirection.expects(:terminus_class=).with(:rest) + + @puppetd.setup + end + + it "should tell the report handler to cache locally as yaml" do + Puppet::Transaction::Report.indirection.expects(:cache_class=).with(:yaml) @puppetd.setup end it "should change the catalog_terminus setting to 'rest'" do - Puppet.expects(:[]=).with(:catalog_terminus, :rest) + Puppet[:catalog_terminus] = :foo @puppetd.setup + Puppet[:catalog_terminus].should == :rest end it "should tell the catalog handler to use cache" do - Puppet::Resource::Catalog.expects(:cache_class=).with(:yaml) + Puppet::Resource::Catalog.indirection.expects(:cache_class=).with(:yaml) @puppetd.setup end it "should change the facts_terminus setting to 'facter'" do - Puppet.expects(:[]=).with(:facts_terminus, :facter) + Puppet[:facts_terminus] = :foo @puppetd.setup + Puppet[:facts_terminus].should == :facter end it "should create an agent" do @@ -374,7 +382,7 @@ describe Puppet::Application::Agent do end it "should daemonize if needed" do - Puppet.stubs(:[]).with(:daemonize).returns(true) + Puppet[:daemonize] = true @daemon.expects(:daemonize) @@ -397,7 +405,7 @@ describe Puppet::Application::Agent do end it "should setup listen if told to and not onetime" do - Puppet.stubs(:[]).with(:listen).returns(true) + Puppet[:listen] = true @puppetd.options.stubs(:[]).with(:onetime).returns(false) @puppetd.expects(:setup_listen) @@ -407,7 +415,7 @@ describe Puppet::Application::Agent do describe "when setting up listen" do before :each do - Puppet.stubs(:[]).with(:authconfig).returns('auth') + Puppet[:authconfig] = 'auth' FileTest.stubs(:exists?).with('auth').returns(true) File.stubs(:exist?).returns(true) @puppetd.options.stubs(:[]).with(:serve).returns([]) @@ -419,7 +427,7 @@ describe Puppet::Application::Agent do it "should exit if no authorization file" do Puppet.stubs(:err) - FileTest.stubs(:exists?).with('auth').returns(false) + FileTest.stubs(:exists?).with(Puppet[:authconfig]).returns(false) @puppetd.expects(:exit) @@ -440,9 +448,9 @@ describe Puppet::Application::Agent do end it "should use puppet default port" do - Puppet.stubs(:[]).with(:puppetport).returns(:port) + Puppet[:puppetport] = 32768 - Puppet::Network::Server.expects(:new).with { |args| args[:port] == :port } + Puppet::Network::Server.expects(:new).with { |args| args[:port] == 32768 } @puppetd.setup_listen end @@ -521,7 +529,7 @@ describe Puppet::Application::Agent do end it "should exit with report's computed exit status" do - Puppet.stubs(:[]).with(:noop).returns(false) + Puppet[:noop] = false report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) @puppetd.expects(:exit).with(666) @@ -530,7 +538,7 @@ describe Puppet::Application::Agent do end it "should always exit with 0 if --noop" do - Puppet.stubs(:[]).with(:noop).returns(true) + Puppet[:noop] = true report = stub 'report', :exit_status => 666 @agent.stubs(:run).returns(report) @puppetd.expects(:exit).with(0) diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb index 877c47bcc..52b84e6f2 100755 --- a/spec/unit/application/apply_spec.rb +++ b/spec/unit/application/apply_spec.rb @@ -4,6 +4,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/apply' require 'puppet/file_bucket/dipper' +require 'puppet/configurer' describe Puppet::Application::Apply do before :each do @@ -56,6 +57,7 @@ describe Puppet::Application::Apply do Puppet.stubs(:parse_config) Puppet::FileBucket::Dipper.stubs(:new) STDIN.stubs(:read) + Puppet::Transaction::Report.indirection.stubs(:cache_class=) @apply.options.stubs(:[]).with(any_parameters) end @@ -113,6 +115,11 @@ describe Puppet::Application::Apply do lambda { @apply.setup }.should raise_error(SystemExit) end + it "should tell the report handler to cache locally as yaml" do + Puppet::Transaction::Report.indirection.expects(:cache_class=).with(:yaml) + + @apply.setup + end end describe "when executing" do @@ -142,17 +149,16 @@ describe Puppet::Application::Apply do describe "the parseonly command" do before :each do - Puppet.stubs(:[]).with(:environment) + @environment = Puppet::Node::Environment.new("env") + Puppet.stubs(:[]).with(:environment).returns(@environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @apply.stubs(:exit) @apply.options.stubs(:[]).with(:code).returns "some code" - @collection = stub_everything - Puppet::Resource::TypeCollection.stubs(:new).returns(@collection) end - it "should use a Puppet Resource Type Collection to parse the file" do - @collection.expects(:perform_initial_import) + it "should use the environment to parse the file" do + @environment.stubs(:perform_initial_import) @apply.parseonly end @@ -162,7 +168,7 @@ describe Puppet::Application::Apply do end it "should exit with exit code 1 if error" do - @collection.stubs(:perform_initial_import).raises(Puppet::ParseError) + @environment.stubs(:perform_initial_import).raises(Puppet::ParseError) @apply.expects(:exit).with(1) @apply.parseonly end @@ -179,14 +185,14 @@ describe Puppet::Application::Apply do @apply.options.stubs(:[]) @facts = stub_everything 'facts' - Puppet::Node::Facts.stubs(:find).returns(@facts) + Puppet::Node::Facts.indirection.stubs(:find).returns(@facts) @node = stub_everything 'node' - Puppet::Node.stubs(:find).returns(@node) + Puppet::Node.indirection.stubs(:find).returns(@node) @catalog = stub_everything 'catalog' @catalog.stubs(:to_ral).returns(@catalog) - Puppet::Resource::Catalog.stubs(:find).returns(@catalog) + Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog) STDIN.stubs(:read) @@ -194,6 +200,9 @@ describe Puppet::Application::Apply do @catalog.stubs(:apply).returns(@transaction) @apply.stubs(:exit) + + Puppet::Util::Storage.stubs(:load) + Puppet::Configurer.any_instance.stubs(:save_last_run_summary) # to prevent it from trying to write files end it "should set the code to run from --code" do @@ -239,25 +248,25 @@ describe Puppet::Application::Apply do end it "should collect the node facts" do - Puppet::Node::Facts.expects(:find).returns(@facts) + Puppet::Node::Facts.indirection.expects(:find).returns(@facts) @apply.main end it "should raise an error if we can't find the node" do - Puppet::Node::Facts.expects(:find).returns(nil) + Puppet::Node::Facts.indirection.expects(:find).returns(nil) lambda { @apply.main }.should raise_error end it "should look for the node" do - Puppet::Node.expects(:find).returns(@node) + Puppet::Node.indirection.expects(:find).returns(@node) @apply.main end it "should raise an error if we can't find the node" do - Puppet::Node.expects(:find).returns(nil) + Puppet::Node.indirection.expects(:find).returns(nil) lambda { @apply.main }.should raise_error end @@ -283,7 +292,7 @@ describe Puppet::Application::Apply do end it "should compile the catalog" do - Puppet::Resource::Catalog.expects(:find).returns(@catalog) + Puppet::Resource::Catalog.indirection.expects(:find).returns(@catalog) @apply.main end @@ -302,11 +311,8 @@ describe Puppet::Application::Apply do end it "should call the prerun and postrun commands on a Configurer instance" do - configurer = stub 'configurer' - - Puppet::Configurer.expects(:new).returns configurer - configurer.expects(:execute_prerun_command) - configurer.expects(:execute_postrun_command) + Puppet::Configurer.any_instance.expects(:execute_prerun_command) + Puppet::Configurer.any_instance.expects(:execute_postrun_command) @apply.main end @@ -317,12 +323,20 @@ describe Puppet::Application::Apply do @apply.main end + it "should save the last run summary" do + Puppet.stubs(:[]).with(:noop).returns(false) + report = stub 'report' + Puppet::Configurer.any_instance.stubs(:initialize_report).returns(report) + + Puppet::Configurer.any_instance.expects(:save_last_run_summary).with(report) + @apply.main + end + describe "with detailed_exitcodes" do it "should exit with report's computed exit status" do Puppet.stubs(:[]).with(:noop).returns(false) @apply.options.stubs(:[]).with(:detailed_exitcodes).returns(true) - report = stub 'report', :exit_status => 666 - @transaction.stubs(:report).returns(report) + Puppet::Transaction::Report.any_instance.stubs(:exit_status).returns(666) @apply.expects(:exit).with(666) @apply.main diff --git a/spec/unit/application/filebucket_spec.rb b/spec/unit/application/filebucket_spec.rb index 6e7a7b819..e6272f179 100644 --- a/spec/unit/application/filebucket_spec.rb +++ b/spec/unit/application/filebucket_spec.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/filebucket' +require 'puppet/file_bucket/dipper' describe Puppet::Application::Filebucket do before :each do diff --git a/spec/unit/application/kick_spec.rb b/spec/unit/application/kick_spec.rb index dea7ec147..5ccf81bd0 100755 --- a/spec/unit/application/kick_spec.rb +++ b/spec/unit/application/kick_spec.rb @@ -163,7 +163,7 @@ describe Puppet::Application::Kick do @kick.options.stubs(:[]).with(:all).returns(true) @kick.stubs(:puts) - Puppet::Node.expects(:search).with("whatever",:fqdn => :something).returns([]) + Puppet::Node.indirection.expects(:search).with("whatever",:fqdn => :something).returns([]) @kick.setup end @@ -172,7 +172,7 @@ describe Puppet::Application::Kick do @kick.options.stubs(:[]).with(:all).returns(true) @kick.stubs(:puts) - Puppet::Node.expects(:search).with("whatever",:fqdn => nil).returns([]) + Puppet::Node.indirection.expects(:search).with("whatever",:fqdn => nil).returns([]) @kick.setup end @@ -182,7 +182,7 @@ describe Puppet::Application::Kick do @kick.stubs(:puts) @kick.classes = ['class'] - Puppet::Node.expects(:search).with("whatever", :class => "class", :fqdn => nil).returns([]) + Puppet::Node.indirection.expects(:search).with("whatever", :class => "class", :fqdn => nil).returns([]) @kick.setup end @@ -279,7 +279,7 @@ describe Puppet::Application::Kick do end it "should call run on a Puppet::Run for the given host" do - @agent_run.expects(:save).with('https://host:8139/production/run/host').returns(@agent_run) + Puppet::Run.indirection.expects(:save).with(@agent_run, 'https://host:8139/production/run/host').returns(@agent_run) @kick.run_for_host('host') end diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb index 216c7dc90..86e38efcb 100644 --- a/spec/unit/application/master_spec.rb +++ b/spec/unit/application/master_spec.rb @@ -14,12 +14,12 @@ describe Puppet::Application::Master do Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) - Puppet::Node.stubs(:terminus_class=) - Puppet::Node.stubs(:cache_class=) - Puppet::Node::Facts.stubs(:terminus_class=) - Puppet::Node::Facts.stubs(:cache_class=) - Puppet::Transaction::Report.stubs(:terminus_class=) - Puppet::Resource::Catalog.stubs(:terminus_class=) + Puppet::Node.indirection.stubs(:terminus_class=) + Puppet::Node.indirection.stubs(:cache_class=) + Puppet::Node::Facts.indirection.stubs(:terminus_class=) + Puppet::Node::Facts.indirection.stubs(:cache_class=) + Puppet::Transaction::Report.indirection.stubs(:terminus_class=) + Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) end it "should operate in master run_mode" do @@ -183,7 +183,7 @@ describe Puppet::Application::Master do end it "should cache class in yaml" do - Puppet::Node.expects(:cache_class=).with(:yaml) + Puppet::Node.indirection.expects(:cache_class=).with(:yaml) @master.setup end @@ -257,16 +257,15 @@ describe Puppet::Application::Master do describe "the parseonly command" do before :each do - Puppet.stubs(:[]).with(:environment) + @environment = Puppet::Node::Environment.new("env") + Puppet.stubs(:[]).with(:environment).returns(@environment) Puppet.stubs(:[]).with(:manifest).returns("site.pp") Puppet.stubs(:err) @master.stubs(:exit) - @collection = stub_everything - Puppet::Resource::TypeCollection.stubs(:new).returns(@collection) end it "should use a Puppet Resource Type Collection to parse the file" do - @collection.expects(:perform_initial_import) + @environment.expects(:perform_initial_import) @master.parseonly end @@ -276,7 +275,7 @@ describe Puppet::Application::Master do end it "should exit with exit code 1 if error" do - @collection.stubs(:perform_initial_import).raises(Puppet::ParseError) + @environment.stubs(:perform_initial_import).raises(Puppet::ParseError) @master.expects(:exit).with(1) @master.parseonly end @@ -299,7 +298,7 @@ describe Puppet::Application::Master do it "should compile a catalog for the specified node" do @master.options[:node] = "foo" - Puppet::Resource::Catalog.expects(:find).with("foo").returns Puppet::Resource::Catalog.new + Puppet::Resource::Catalog.indirection.expects(:find).with("foo").returns Puppet::Resource::Catalog.new $stdout.stubs(:puts) @master.compile @@ -307,7 +306,7 @@ describe Puppet::Application::Master do it "should convert the catalog to a pure-resource catalog and use 'jj' to pretty-print the catalog" do catalog = Puppet::Resource::Catalog.new - Puppet::Resource::Catalog.expects(:find).returns catalog + Puppet::Resource::Catalog.indirection.expects(:find).returns catalog catalog.expects(:to_resource).returns("rescat") @@ -319,7 +318,7 @@ describe Puppet::Application::Master do it "should exit with error code 30 if no catalog can be found" do @master.options[:node] = "foo" - Puppet::Resource::Catalog.expects(:find).returns nil + Puppet::Resource::Catalog.indirection.expects(:find).returns nil @master.expects(:exit).with(30) $stderr.expects(:puts) @@ -328,7 +327,7 @@ describe Puppet::Application::Master do it "should exit with error code 30 if there's a failure" do @master.options[:node] = "foo" - Puppet::Resource::Catalog.expects(:find).raises ArgumentError + Puppet::Resource::Catalog.indirection.expects(:find).raises ArgumentError @master.expects(:exit).with(30) $stderr.expects(:puts) diff --git a/spec/unit/application/queue_spec.rb b/spec/unit/application/queue_spec.rb index 87c96dfff..1c65b558c 100755 --- a/spec/unit/application/queue_spec.rb +++ b/spec/unit/application/queue_spec.rb @@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/application/queue' +require 'puppet/indirector/catalog/queue' describe Puppet::Application::Queue do before :each do @@ -12,7 +13,7 @@ describe Puppet::Application::Queue do Puppet::Util::Log.stubs(:newdestination) Puppet::Util::Log.stubs(:level=) - Puppet::Resource::Catalog.stubs(:terminus_class=) + Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) end it "should ask Puppet::Application to parse Puppet configuration file" do @@ -79,7 +80,7 @@ describe Puppet::Application::Queue do @queue.daemon.stubs(:daemonize) Puppet.stubs(:info) Puppet.features.stubs(:stomp?).returns true - Puppet::Resource::Catalog.stubs(:terminus_class=) + Puppet::Resource::Catalog.indirection.stubs(:terminus_class=) Puppet.stubs(:settraps) Puppet.settings.stubs(:print_config?) Puppet.settings.stubs(:print_config) @@ -143,7 +144,7 @@ describe Puppet::Application::Queue do end it "should configure the Catalog class to use ActiveRecord" do - Puppet::Resource::Catalog.expects(:terminus_class=).with(:active_record) + Puppet::Resource::Catalog.indirection.expects(:terminus_class=).with(:active_record) @queue.setup end @@ -170,8 +171,8 @@ describe Puppet::Application::Queue do end it "should log and save each catalog passed by the queue" do - catalog = mock 'catalog', :name => 'eh' - catalog.expects(:save) + catalog = Puppet::Resource::Catalog.new('eh') + Puppet::Resource::Catalog.indirection.expects(:save).with(catalog) Puppet::Resource::Catalog::Queue.expects(:subscribe).yields(catalog) Puppet.expects(:notice).times(2) diff --git a/spec/unit/application/resource_spec.rb b/spec/unit/application/resource_spec.rb index b6c52b11e..df479ac89 100755 --- a/spec/unit/application/resource_spec.rb +++ b/spec/unit/application/resource_spec.rb @@ -162,21 +162,21 @@ describe Puppet::Application::Resource do @resource.stubs(:puts) @resource.host = 'host' - Puppet::Resource.stubs(:find ).never - Puppet::Resource.stubs(:search).never - Puppet::Resource.stubs(:save ).never + Puppet::Resource.indirection.stubs(:find ).never + Puppet::Resource.indirection.stubs(:search).never + Puppet::Resource.indirection.stubs(:save ).never end it "should search for resources" do @resource.command_line.stubs(:args).returns(['type']) - Puppet::Resource.expects(:search).with('https://host:8139/production/resources/type/', {}).returns([]) + Puppet::Resource.indirection.expects(:search).with('https://host:8139/production/resources/type/', {}).returns([]) @resource.main end it "should describe the given resource" do @resource.command_line.stubs(:args).returns(['type', 'name']) x = stub_everything 'resource' - Puppet::Resource.expects(:find).with('https://host:8139/production/resources/type/name').returns(x) + Puppet::Resource.indirection.expects(:find).with('https://host:8139/production/resources/type/name').returns(x) @resource.main end @@ -184,7 +184,7 @@ describe Puppet::Application::Resource do @resource.command_line.stubs(:args).returns(['type','name','param=temp']) res = stub "resource" - res.expects(:save).with('https://host:8139/production/resources/type/name').returns(res) + Puppet::Resource.indirection.expects(:save).with(res, 'https://host:8139/production/resources/type/name').returns(res) res.expects(:collect) res.expects(:to_manifest) Puppet::Resource.expects(:new).with('type', 'name', :parameters => {'param' => 'temp'}).returns(res) @@ -199,20 +199,20 @@ describe Puppet::Application::Resource do @resource.stubs(:puts) @resource.host = nil - Puppet::Resource.stubs(:find ).never - Puppet::Resource.stubs(:search).never - Puppet::Resource.stubs(:save ).never + Puppet::Resource.indirection.stubs(:find ).never + Puppet::Resource.indirection.stubs(:search).never + Puppet::Resource.indirection.stubs(:save ).never end it "should search for resources" do - Puppet::Resource.expects(:search).with('type/', {}).returns([]) + Puppet::Resource.indirection.expects(:search).with('type/', {}).returns([]) @resource.main end it "should describe the given resource" do @resource.command_line.stubs(:args).returns(['type','name']) x = stub_everything 'resource' - Puppet::Resource.expects(:find).with('type/name').returns(x) + Puppet::Resource.indirection.expects(:find).with('type/name').returns(x) @resource.main end @@ -220,7 +220,7 @@ describe Puppet::Application::Resource do @resource.command_line.stubs(:args).returns(['type','name','param=temp']) res = stub "resource" - res.expects(:save).with('type/name').returns(res) + Puppet::Resource.indirection.expects(:save).with(res, 'type/name').returns(res) res.expects(:collect) res.expects(:to_manifest) Puppet::Resource.expects(:new).with('type', 'name', :parameters => {'param' => 'temp'}).returns(res) diff --git a/spec/unit/configurer/fact_handler_spec.rb b/spec/unit/configurer/fact_handler_spec.rb index 051270144..70918c039 100755 --- a/spec/unit/configurer/fact_handler_spec.rb +++ b/spec/unit/configurer/fact_handler_spec.rb @@ -66,7 +66,7 @@ describe Puppet::Configurer::FactHandler do it "should use the Facts class with the :certname to find the facts" do Puppet.settings.expects(:value).with(:certname).returns "foo" - Puppet::Node::Facts.expects(:find).with("foo").returns "myfacts" + Puppet::Node::Facts.indirection.expects(:find).with("foo").returns "myfacts" @facthandler.stubs(:reload_facter) @facthandler.find_facts.should == "myfacts" end @@ -75,7 +75,7 @@ describe Puppet::Configurer::FactHandler do @facthandler.expects(:reload_facter) Puppet.settings.expects(:value).with(:certname).returns "myhost" - Puppet::Node::Facts.expects(:find).with("myhost") + Puppet::Node::Facts.indirection.expects(:find).with("myhost") @facthandler.find_facts end @@ -85,7 +85,7 @@ describe Puppet::Configurer::FactHandler do Puppet.settings.stubs(:value).with(:trace).returns false Puppet.settings.stubs(:value).with(:certname).returns "myhost" - Puppet::Node::Facts.expects(:find).raises RuntimeError + Puppet::Node::Facts.indirection.expects(:find).raises RuntimeError lambda { @facthandler.find_facts }.should raise_error(Puppet::Error) end diff --git a/spec/unit/configurer_spec.rb b/spec/unit/configurer_spec.rb index 0c9d06362..fc718fa58 100755 --- a/spec/unit/configurer_spec.rb +++ b/spec/unit/configurer_spec.rb @@ -89,9 +89,7 @@ describe Puppet::Configurer, "when executing a catalog run" do @catalog = Puppet::Resource::Catalog.new @catalog.stubs(:apply) @agent.stubs(:retrieve_catalog).returns @catalog - - Puppet::Util::Log.stubs(:newdestination) - Puppet::Util::Log.stubs(:close) + @agent.stubs(:save_last_run_summary) end it "should prepare for the run" do @@ -101,14 +99,14 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should initialize a transaction report if one is not provided" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.run end it "should pass the new report to the catalog" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.stubs(:initialize_report).returns report @catalog.expects(:apply).with{|options| options[:report] == report} @@ -116,7 +114,7 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should use the provided report if it was passed one" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).never @catalog.expects(:apply).with{|options| options[:report] == report} @@ -176,7 +174,7 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should send the report" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.expects(:send_report).with { |r, trans| r == report } @@ -184,7 +182,7 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should send the transaction report with a reference to the transaction if a run was actually made" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report trans = stub 'transaction' @@ -198,7 +196,7 @@ describe Puppet::Configurer, "when executing a catalog run" do it "should send the transaction report even if the catalog could not be retrieved" do @agent.expects(:retrieve_catalog).returns nil - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.expects(:send_report) @@ -208,7 +206,7 @@ describe Puppet::Configurer, "when executing a catalog run" do it "should send the transaction report even if there is a failure" do @agent.expects(:retrieve_catalog).raises "whatever" - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.expects(:send_report) @@ -216,16 +214,16 @@ describe Puppet::Configurer, "when executing a catalog run" do end it "should remove the report as a log destination when the run is finished" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report - - Puppet::Util::Log.expects(:close).with(report) + report.expects(:<<).at_least_once @agent.run + Puppet::Util::Log.destinations.should_not include(report) end it "should return the report as the result of the run" do - report = stub 'report' + report = Puppet::Transaction::Report.new @agent.expects(:initialize_report).returns report @agent.run.should equal(report) @@ -236,8 +234,9 @@ describe Puppet::Configurer, "when sending a report" do before do Puppet.settings.stubs(:use).returns(true) @configurer = Puppet::Configurer.new + @configurer.stubs(:save_last_run_summary) - @report = stub 'report' + @report = Puppet::Transaction::Report.new @trans = stub 'transaction' end @@ -273,7 +272,7 @@ describe Puppet::Configurer, "when sending a report" do it "should save the report if reporting is enabled" do Puppet.settings[:report] = true - @report.expects(:save) + Puppet::Transaction::Report.indirection.expects(:save).with(@report) @configurer.send_report(@report) end @@ -284,16 +283,60 @@ describe Puppet::Configurer, "when sending a report" do @configurer.send_report(@report) end + it "should save the last run summary if reporting is enabled" do + Puppet.settings[:report] = true + + @configurer.expects(:save_last_run_summary).with(@report) + @configurer.send_report(@report) + end + + it "should not save the last run summary if reporting is disabled" do + Puppet.settings[:report] = false + + @configurer.expects(:save_last_run_summary).never + @configurer.send_report(@report) + end + it "should log but not fail if saving the report fails" do Puppet.settings[:report] = true - @report.expects(:save).raises "whatever" + Puppet::Transaction::Report.indirection.expects(:save).with(@report).raises "whatever" Puppet.expects(:err) lambda { @configurer.send_report(@report) }.should_not raise_error end end +describe Puppet::Configurer, "when saving the summary report file" do + before do + Puppet.settings.stubs(:use).returns(true) + @configurer = Puppet::Configurer.new + + @report = stub 'report' + @trans = stub 'transaction' + @lastrunfd = stub 'lastrunfd' + Puppet::Util::FileLocking.stubs(:writelock).yields(@lastrunfd) + end + + it "should write the raw summary to the lastrunfile setting value" do + Puppet::Util::FileLocking.expects(:writelock).with(Puppet[:lastrunfile], 0660) + @configurer.save_last_run_summary(@report) + end + + it "should write the raw summary as yaml" do + @report.expects(:raw_summary).returns("summary") + @lastrunfd.expects(:print).with(YAML.dump("summary")) + @configurer.save_last_run_summary(@report) + end + + it "should log but not fail if saving the last run summary fails" do + Puppet::Util::FileLocking.expects(:writelock).raises "exception" + Puppet.expects(:err) + lambda { @configurer.save_last_run_summary(@report) }.should_not raise_error + end + +end + describe Puppet::Configurer, "when retrieving a catalog" do before do Puppet.settings.stubs(:use).returns(true) @@ -314,15 +357,15 @@ describe Puppet::Configurer, "when retrieving a catalog" do end it "should first look in the cache for a catalog" do - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.never + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.never @agent.retrieve_catalog.should == @catalog end it "should compile a new catalog if none is found in the cache" do - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end @@ -331,7 +374,7 @@ describe Puppet::Configurer, "when retrieving a catalog" do describe "when not using a REST terminus for catalogs" do it "should not pass any facts when retrieving the catalog" do @agent.expects(:facts_for_uploading).never - Puppet::Resource::Catalog.expects(:find).with { |name, options| + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:facts].nil? }.returns @catalog @@ -342,7 +385,7 @@ describe Puppet::Configurer, "when retrieving a catalog" do describe "when using a REST terminus for catalogs" do it "should pass the prepared facts and the facts format as arguments when retrieving the catalog" do @agent.expects(:facts_for_uploading).returns(:facts => "myfacts", :facts_format => :foo) - Puppet::Resource::Catalog.expects(:find).with { |name, options| + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:facts] == "myfacts" and options[:facts_format] == :foo }.returns @catalog @@ -351,7 +394,7 @@ describe Puppet::Configurer, "when retrieving a catalog" do end it "should use the Catalog class to get its catalog" do - Puppet::Resource::Catalog.expects(:find).returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).returns @catalog @agent.retrieve_catalog end @@ -359,20 +402,20 @@ describe Puppet::Configurer, "when retrieving a catalog" do it "should use its certname to retrieve the catalog" do Facter.stubs(:value).returns "eh" Puppet.settings[:certname] = "myhost.domain.com" - Puppet::Resource::Catalog.expects(:find).with { |name, options| name == "myhost.domain.com" }.returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| name == "myhost.domain.com" }.returns @catalog @agent.retrieve_catalog end it "should default to returning a catalog retrieved directly from the server, skipping the cache" do - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end it "should log and return the cached catalog when no catalog can be retrieved from the server" do - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog Puppet.expects(:notice) @@ -380,15 +423,15 @@ describe Puppet::Configurer, "when retrieving a catalog" do end it "should not look in the cache for a catalog if one is returned from the server" do - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.never + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.never @agent.retrieve_catalog.should == @catalog end it "should return the cached catalog when retrieving the remote catalog throws an exception" do - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.raises "eh" - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.raises "eh" + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns @catalog @agent.retrieve_catalog.should == @catalog end @@ -396,7 +439,7 @@ describe Puppet::Configurer, "when retrieving a catalog" do it "should log and return nil if no catalog can be retrieved from the server and :usecacheonfailure is disabled" do Puppet.stubs(:[]) Puppet.expects(:[]).with(:usecacheonfailure).returns false - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil Puppet.expects(:warning) @@ -404,21 +447,21 @@ describe Puppet::Configurer, "when retrieving a catalog" do end it "should return nil if no cached catalog is available and no catalog can be retrieved from the server" do - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil - Puppet::Resource::Catalog.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_cache] == true }.returns nil + Puppet::Resource::Catalog.indirection.expects(:find).with { |name, options| options[:ignore_terminus] == true }.returns nil @agent.retrieve_catalog.should be_nil end it "should convert the catalog before returning" do - Puppet::Resource::Catalog.stubs(:find).returns @catalog + Puppet::Resource::Catalog.indirection.stubs(:find).returns @catalog @agent.expects(:convert_catalog).with { |cat, dur| cat == @catalog }.returns "converted catalog" @agent.retrieve_catalog.should == "converted catalog" end it "should return nil if there is an error while retrieving the catalog" do - Puppet::Resource::Catalog.expects(:find).raises "eh" + Puppet::Resource::Catalog.indirection.expects(:find).raises "eh" @agent.retrieve_catalog.should be_nil end @@ -472,23 +515,23 @@ describe Puppet::Configurer, "when preparing for a run" do it "should initialize the metadata store" do @agent.class.stubs(:facts).returns(@facts) @agent.expects(:dostorage) - @agent.prepare + @agent.prepare({}) end it "should download fact plugins" do @agent.expects(:download_fact_plugins) - @agent.prepare + @agent.prepare({}) end it "should download plugins" do @agent.expects(:download_plugins) - @agent.prepare + @agent.prepare({}) end it "should perform the pre-run commands" do @agent.expects(:execute_prerun_command) - @agent.prepare + @agent.prepare({}) end end diff --git a/spec/unit/dsl/resource_type_api_spec.rb b/spec/unit/dsl/resource_type_api_spec.rb index 4f4eb7e01..c9a5d272f 100755 --- a/spec/unit/dsl/resource_type_api_spec.rb +++ b/spec/unit/dsl/resource_type_api_spec.rb @@ -5,62 +5,50 @@ require File.dirname(__FILE__) + '/../../spec_helper' require 'puppet/dsl/resource_type_api' describe Puppet::DSL::ResourceTypeAPI do - # Run the given block in the context of a new ResourceTypeAPI - # object. + # Verify that the block creates a single AST node through the API, + # instantiate that AST node into a types, and return that type. def test_api_call(&block) - Thread.current[:known_resource_types] = Puppet::Resource::TypeCollection.new(:env) - Puppet::DSL::ResourceTypeAPI.new.instance_eval(&block) + main_object = Puppet::DSL::ResourceTypeAPI.new + main_object.instance_eval(&block) + created_ast_objects = main_object.instance_eval { @__created_ast_objects__ } + created_ast_objects.length.should == 1 + new_types = created_ast_objects[0].instantiate('') + new_types.length.should == 1 + new_types[0] ensure - Thread.current[:known_resource_types] = nil + Thread.current[:ruby_file_parse_result] = nil end [:definition, :node, :hostclass].each do |type| method = type == :definition ? "define" : type it "should be able to create a #{type}" do - newtype = Puppet::Resource::Type.new(:hostclass, "foo") - Puppet::Resource::Type.expects(:new).with { |t, n, args| t == type }.returns newtype - test_api_call { send(method, "myname") } + newtype = test_api_call { send(method, "myname").should == nil } + newtype.should be_a(Puppet::Resource::Type) + newtype.type.should == type end it "should use the provided name when creating a #{type}" do - type = Puppet::Resource::Type.new(:hostclass, "foo") - Puppet::Resource::Type.expects(:new).with { |t, n, args| n == "myname" }.returns type - test_api_call { send(method, "myname") } + newtype = test_api_call { send(method, "myname") } + newtype.name.should == "myname" end unless type == :definition - it "should pass in any provided options" do - type = Puppet::Resource::Type.new(:hostclass, "foo") - Puppet::Resource::Type.expects(:new).with { |t, n, args| args == {:myarg => :myvalue} }.returns type - test_api_call { send(method, "myname", :myarg => :myvalue) } + it "should pass in any provided options when creating a #{type}" do + newtype = test_api_call { send(method, "myname", :line => 200) } + newtype.line.should == 200 end end it "should set any provided block as the type's ruby code" do - Puppet::Resource::Type.any_instance.expects(:ruby_code=).with { |blk| blk.call == 'foo' } - test_api_call { send(method, "myname") { 'foo' } } - end - - it "should add the type to the current environment's known resource types" do - begin - newtype = Puppet::Resource::Type.new(:hostclass, "foo") - Puppet::Resource::Type.expects(:new).returns newtype - known_resource_types = Puppet::Resource::TypeCollection.new(:env) - Thread.current[:known_resource_types] = known_resource_types - known_resource_types.expects(:add).with(newtype) - Puppet::DSL::ResourceTypeAPI.new.instance_eval { hostclass "myname" } - ensure - Thread.current[:known_resource_types] = nil - end + newtype = test_api_call { send(method, "myname") { 'method_result' } } + newtype.ruby_code.call.should == 'method_result' end end describe "when creating a definition" do it "should use the provided options to define valid arguments for the resource type" do - newtype = Puppet::Resource::Type.new(:definition, "foo") - Puppet::Resource::Type.expects(:new).returns newtype - test_api_call { define("myname", :arg1, :arg2) } - newtype.instance_eval { @arguments }.should == { 'arg1' => nil, 'arg2' => nil } + newtype = test_api_call { define("myname", :arg1, :arg2) } + newtype.arguments.should == { 'arg1' => nil, 'arg2' => nil } end end end diff --git a/spec/unit/file_bucket/dipper_spec.rb b/spec/unit/file_bucket/dipper_spec.rb index 799e899e7..46d314d1f 100755 --- a/spec/unit/file_bucket/dipper_spec.rb +++ b/spec/unit/file_bucket/dipper_spec.rb @@ -16,10 +16,9 @@ describe Puppet::FileBucket::Dipper do @dipper = Puppet::FileBucket::Dipper.new(:Path => "/my/bucket") - filemock = stub "bucketfile" - Puppet::FileBucket::File.stubs(:new).returns(filemock) - filemock.expects(:name).returns "name" - filemock.expects(:save).raises ArgumentError + Puppet::FileBucket::File.any_instance.stubs(:validate_checksum!) + file = Puppet::FileBucket::File.new(nil) + Puppet::FileBucket::File.indirection.expects(:save).raises ArgumentError lambda { @dipper.backup("/my/file") }.should raise_error(Puppet::Error) end @@ -32,10 +31,9 @@ describe Puppet::FileBucket::Dipper do File.stubs(:exist?).returns true File.stubs(:read).with("/my/file").returns "my contents" - bucketfile = stub "bucketfile" - bucketfile.stubs(:name).returns('md5/DIGEST123') - bucketfile.stubs(:checksum_data).returns("DIGEST123") - bucketfile.expects(:save).with('md5/DIGEST123') + Puppet::FileBucket::File.any_instance.stubs(:validate_checksum!) + bucketfile = Puppet::FileBucket::File.new(nil, :checksum_type => "md5", :checksum => "{md5}DIGEST123") + Puppet::FileBucket::File.indirection.expects(:save).with(bucketfile, 'md5/DIGEST123') Puppet::FileBucket::File.stubs(:new).with( @@ -60,7 +58,7 @@ describe Puppet::FileBucket::Dipper do bucketfile = stub "bucketfile" bucketfile.stubs(:to_s).returns "Content" - Puppet::FileBucket::File.expects(:find).with{|x,opts| + Puppet::FileBucket::File.indirection.expects(:find).with{|x,opts| x == 'md5/DIGEST123' }.returns(bucketfile) @@ -79,10 +77,9 @@ describe Puppet::FileBucket::Dipper do File.stubs(:exist?).returns true File.stubs(:read).with("/my/file").returns "my contents" - bucketfile = stub "bucketfile" - bucketfile.stubs(:name).returns('md5/DIGEST123') - bucketfile.stubs(:checksum_data).returns("DIGEST123") - bucketfile.expects(:save).with('https://puppetmaster:31337/production/file_bucket_file/md5/DIGEST123') + Puppet::FileBucket::File.any_instance.stubs(:validate_checksum!) + bucketfile = Puppet::FileBucket::File.new(nil, :checksum_type => "md5", :checksum => "{md5}DIGEST123") + Puppet::FileBucket::File.indirection.expects(:save).with(bucketfile, 'https://puppetmaster:31337/production/file_bucket_file/md5/DIGEST123') Puppet::FileBucket::File.stubs(:new).with( @@ -111,7 +108,7 @@ describe Puppet::FileBucket::Dipper do bucketfile = stub "bucketfile" bucketfile.stubs(:to_s).returns "Content" - Puppet::FileBucket::File.expects(:find).with{|x,opts| + Puppet::FileBucket::File.indirection.expects(:find).with{|x,opts| x == 'https://puppetmaster:31337/production/file_bucket_file/md5/DIGEST123' }.returns(bucketfile) diff --git a/spec/unit/file_bucket/file_spec.rb b/spec/unit/file_bucket/file_spec.rb index 3ad70c203..b9849b0fc 100644 --- a/spec/unit/file_bucket/file_spec.rb +++ b/spec/unit/file_bucket/file_spec.rb @@ -95,15 +95,7 @@ describe Puppet::FileBucket::File do end it "should have a :save instance method" do - Puppet::FileBucket::File.new("mysum").should respond_to(:save) - end - - it "should respond to :find" do - Puppet::FileBucket::File.should respond_to(:find) - end - - it "should respond to :destroy" do - Puppet::FileBucket::File.should respond_to(:destroy) + Puppet::FileBucket::File.indirection.should respond_to(:save) end end @@ -116,7 +108,7 @@ describe Puppet::FileBucket::File do mockfile.expects(:print).with(@contents) ::File.expects(:open).with("#{@dir}/contents", ::File::WRONLY|::File::CREAT, 0440).yields(mockfile) - Puppet::FileBucket::File.new(@contents).save + Puppet::FileBucket::File.indirection.save(Puppet::FileBucket::File.new(@contents)) end it "should make any directories necessary for storage" do @@ -127,7 +119,7 @@ describe Puppet::FileBucket::File do ::File.expects(:open).with("#{@dir}/contents", ::File::WRONLY|::File::CREAT, 0440) ::File.expects(:exist?).with("#{@dir}/contents").returns false - Puppet::FileBucket::File.new(@contents).save + Puppet::FileBucket::File.indirection.save(Puppet::FileBucket::File.new(@contents)) end it "should append the path to the paths file" do @@ -141,7 +133,7 @@ describe Puppet::FileBucket::File do mockfile.expects(:puts).with('/path/on/the/remote/box') ::File.expects(:exist?).with("#{@dir}/paths").returns false ::File.expects(:open).with("#{@dir}/paths", ::File::WRONLY|::File::CREAT|::File::APPEND).yields mockfile - Puppet::FileBucket::File.new(@contents, :path => remote_path).save + Puppet::FileBucket::File.indirection.save(Puppet::FileBucket::File.new(@contents, :path => remote_path)) end end @@ -187,7 +179,7 @@ describe Puppet::FileBucket::File do ::File.expects(:open).with("#{@dir}/contents", ::File::WRONLY|::File::CREAT, 0440) bucketfile = Puppet::FileBucket::File.new(@contents) - bucketfile.save + Puppet::FileBucket::File.indirection.save(bucketfile) end @@ -195,7 +187,7 @@ describe Puppet::FileBucket::File do it "should return nil if a file doesn't exist" do ::File.expects(:exist?).with("#{@dir}/contents").returns false - bucketfile = Puppet::FileBucket::File.find("{md5}#{@digest}") + bucketfile = Puppet::FileBucket::File.indirection.find("{md5}#{@digest}") bucketfile.should == nil end @@ -204,7 +196,7 @@ describe Puppet::FileBucket::File do ::File.expects(:exist?).with("#{@dir}/paths").returns false ::File.expects(:read).with("#{@dir}/contents").returns @contents - bucketfile = Puppet::FileBucket::File.find("{md5}#{@digest}") + bucketfile = Puppet::FileBucket::File.indirection.find("{md5}#{@digest}") bucketfile.should_not == nil end @@ -212,7 +204,7 @@ describe Puppet::FileBucket::File do it "should return nil if a file doesn't exist" do ::File.expects(:exist?).with("#{@dir}/contents").returns false - bucketfile = Puppet::FileBucket::File.find("md5/#{@digest}") + bucketfile = Puppet::FileBucket::File.indirection.find("md5/#{@digest}") bucketfile.should == nil end @@ -221,7 +213,7 @@ describe Puppet::FileBucket::File do ::File.expects(:exist?).with("#{@dir}/paths").returns false ::File.expects(:read).with("#{@dir}/contents").returns @contents - bucketfile = Puppet::FileBucket::File.find("md5/#{@digest}") + bucketfile = Puppet::FileBucket::File.indirection.find("md5/#{@digest}") bucketfile.should_not == nil end diff --git a/spec/unit/indirector/active_record_spec.rb b/spec/unit/indirector/active_record_spec.rb index 258c4e793..40af146c8 100755 --- a/spec/unit/indirector/active_record_spec.rb +++ b/spec/unit/indirector/active_record_spec.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' require 'puppet/indirector/active_record' describe Puppet::Indirector::ActiveRecord do diff --git a/spec/unit/indirector/catalog/active_record_spec.rb b/spec/unit/indirector/catalog/active_record_spec.rb index 4e9d049a1..09e943376 100755 --- a/spec/unit/indirector/catalog/active_record_spec.rb +++ b/spec/unit/indirector/catalog/active_record_spec.rb @@ -80,7 +80,7 @@ describe "Puppet::Resource::Catalog::ActiveRecord" do @host.stubs(:railsmark).yields @node = stub_everything 'node', :parameters => {} - Puppet::Node.stubs(:find).returns(@node) + Puppet::Node.indirection.stubs(:find).returns(@node) Puppet::Rails::Host.stubs(:find_by_name).returns @host @catalog = Puppet::Resource::Catalog.new("foo") diff --git a/spec/unit/indirector/catalog/compiler_spec.rb b/spec/unit/indirector/catalog/compiler_spec.rb index 6c950b626..c8c53aecc 100755 --- a/spec/unit/indirector/catalog/compiler_spec.rb +++ b/spec/unit/indirector/catalog/compiler_spec.rb @@ -10,6 +10,7 @@ require 'puppet/rails' describe Puppet::Resource::Catalog::Compiler do before do + require 'puppet/rails' Puppet::Rails.stubs(:init) Facter.stubs(:to_hash).returns({}) Facter.stubs(:value).returns(Facter::Util::Fact.new("something")) @@ -31,8 +32,8 @@ describe Puppet::Resource::Catalog::Compiler do node1 = stub 'node1', :merge => nil node2 = stub 'node2', :merge => nil compiler.stubs(:compile) - Puppet::Node.stubs(:find).with('node1').returns(node1) - Puppet::Node.stubs(:find).with('node2').returns(node2) + Puppet::Node.indirection.stubs(:find).with('node1').returns(node1) + Puppet::Node.indirection.stubs(:find).with('node2').returns(node2) compiler.find(stub('request', :key => 'node1', :node => 'node1', :options => {})) compiler.find(stub('node2request', :key => 'node2', :node => 'node2', :options => {})) @@ -70,12 +71,12 @@ describe Puppet::Resource::Catalog::Compiler do @name = "me" @node = Puppet::Node.new @name @node.stubs(:merge) - Puppet::Node.stubs(:find).returns @node + Puppet::Node.indirection.stubs(:find).returns @node @request = stub 'request', :key => @name, :node => @name, :options => {} end it "should directly use provided nodes" do - Puppet::Node.expects(:find).never + Puppet::Node.indirection.expects(:find).never @compiler.expects(:compile).with(@node) @request.stubs(:options).returns(:use_node => @node) @compiler.find(@request) @@ -83,7 +84,7 @@ describe Puppet::Resource::Catalog::Compiler do it "should use the authenticated node name if no request key is provided" do @request.stubs(:key).returns(nil) - Puppet::Node.expects(:find).with(@name).returns(@node) + Puppet::Node.indirection.expects(:find).with(@name).returns(@node) @compiler.expects(:compile).with(@node) @compiler.find(@request) end @@ -91,37 +92,37 @@ describe Puppet::Resource::Catalog::Compiler do it "should use the provided node name by default" do @request.expects(:key).returns "my_node" - Puppet::Node.expects(:find).with("my_node").returns @node + Puppet::Node.indirection.expects(:find).with("my_node").returns @node @compiler.expects(:compile).with(@node) @compiler.find(@request) end it "should fail if no node is passed and none can be found" do - Puppet::Node.stubs(:find).with(@name).returns(nil) + Puppet::Node.indirection.stubs(:find).with(@name).returns(nil) proc { @compiler.find(@request) }.should raise_error(ArgumentError) end it "should fail intelligently when searching for a node raises an exception" do - Puppet::Node.stubs(:find).with(@name).raises "eh" + Puppet::Node.indirection.stubs(:find).with(@name).raises "eh" proc { @compiler.find(@request) }.should raise_error(Puppet::Error) end it "should pass the found node to the compiler for compiling" do - Puppet::Node.expects(:find).with(@name).returns(@node) + Puppet::Node.indirection.expects(:find).with(@name).returns(@node) config = mock 'config' Puppet::Parser::Compiler.expects(:compile).with(@node) @compiler.find(@request) end it "should extract and save any facts from the request" do - Puppet::Node.expects(:find).with(@name).returns @node + Puppet::Node.indirection.expects(:find).with(@name).returns @node @compiler.expects(:extract_facts_from_request).with(@request) Puppet::Parser::Compiler.stubs(:compile) @compiler.find(@request) end it "should return the results of compiling as the catalog" do - Puppet::Node.stubs(:find).returns(@node) + Puppet::Node.indirection.stubs(:find).returns(@node) config = mock 'config' result = mock 'result' @@ -130,7 +131,7 @@ describe Puppet::Resource::Catalog::Compiler do end it "should benchmark the compile process" do - Puppet::Node.stubs(:find).returns(@node) + Puppet::Node.indirection.stubs(:find).returns(@node) @compiler.stubs(:networked?).returns(true) @compiler.expects(:benchmark).with do |level, message| level == :notice and message =~ /^Compiled catalog/ @@ -140,7 +141,7 @@ describe Puppet::Resource::Catalog::Compiler do end it "should log the benchmark result" do - Puppet::Node.stubs(:find).returns(@node) + Puppet::Node.indirection.stubs(:find).returns(@node) @compiler.stubs(:networked?).returns(true) Puppet::Parser::Compiler.stubs(:compile) @@ -156,22 +157,28 @@ describe Puppet::Resource::Catalog::Compiler do @compiler = Puppet::Resource::Catalog::Compiler.new @request = stub 'request', :options => {} - @facts = stub 'facts', :save => nil + @facts = Puppet::Node::Facts.new('hostname', "fact" => "value", "architecture" => "i386") + Puppet::Node::Facts.indirection.stubs(:save).returns(nil) end it "should do nothing if no facts are provided" do - Puppet::Node::Facts.expects(:convert_from).never + Puppet::Node::Facts.indirection.expects(:convert_from).never @request.options[:facts] = nil @compiler.extract_facts_from_request(@request) end - it "should use the Facts class to deserialize the provided facts" do + it "should use the Facts class to deserialize the provided facts and update the timestamp" do @request.options[:facts_format] = "foo" @request.options[:facts] = "bar" Puppet::Node::Facts.expects(:convert_from).returns @facts + @facts.timestamp = Time.parse('2010-11-01') + @now = Time.parse('2010-11-02') + Time.expects(:now).returns(@now) + @compiler.extract_facts_from_request(@request) + @facts.timestamp.should == @now end it "should use the provided fact format" do @@ -187,7 +194,7 @@ describe Puppet::Resource::Catalog::Compiler do @request.options[:facts] = "bar" Puppet::Node::Facts.expects(:convert_from).returns @facts - @facts.expects(:save) + Puppet::Node::Facts.indirection.expects(:save).with(@facts) @compiler.extract_facts_from_request(@request) end @@ -205,7 +212,7 @@ describe Puppet::Resource::Catalog::Compiler do it "should look node information up via the Node class with the provided key" do @node.stubs :merge - Puppet::Node.expects(:find).with(@name).returns(@node) + Puppet::Node.indirection.expects(:find).with(@name).returns(@node) @compiler.find(@request) end end @@ -220,7 +227,7 @@ describe Puppet::Resource::Catalog::Compiler do @node = mock 'node' @request = stub 'request', :key => @name, :options => {} @compiler.stubs(:compile) - Puppet::Node.stubs(:find).with(@name).returns(@node) + Puppet::Node.indirection.stubs(:find).with(@name).returns(@node) end it "should add the server's Puppet version to the node's parameters as 'serverversion'" do diff --git a/spec/unit/indirector/facts/active_record_spec.rb b/spec/unit/indirector/facts/active_record_spec.rb index 0cdb70e01..0bdcfcb77 100755 --- a/spec/unit/indirector/facts/active_record_spec.rb +++ b/spec/unit/indirector/facts/active_record_spec.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../../spec_helper' +require 'puppet/rails' require 'puppet/node/facts' describe "Puppet::Node::Facts::ActiveRecord" do diff --git a/spec/unit/indirector/facts/yaml_spec.rb b/spec/unit/indirector/facts/yaml_spec.rb index e7bac3471..37a1bcae0 100755 --- a/spec/unit/indirector/facts/yaml_spec.rb +++ b/spec/unit/indirector/facts/yaml_spec.rb @@ -10,9 +10,9 @@ describe Puppet::Node::Facts::Yaml do Puppet::Node::Facts::Yaml.superclass.should equal(Puppet::Indirector::Yaml) end - it "should have documentation" do Puppet::Node::Facts::Yaml.doc.should_not be_nil + Puppet::Node::Facts::Yaml.doc.should_not be_empty end it "should be registered with the facts indirection" do @@ -20,7 +20,7 @@ describe Puppet::Node::Facts::Yaml do Puppet::Node::Facts::Yaml.indirection.should equal(indirection) end - it "should have its name set to :facts" do + it "should have its name set to :yaml" do Puppet::Node::Facts::Yaml.name.should == :yaml end end diff --git a/spec/unit/indirector/indirection_spec.rb b/spec/unit/indirector/indirection_spec.rb index b0e0f019c..f49d94f8e 100755 --- a/spec/unit/indirector/indirection_spec.rb +++ b/spec/unit/indirector/indirection_spec.rb @@ -386,9 +386,6 @@ describe Puppet::Indirector::Indirection do describe "and storing a model instance" do before { @method = :save } - it_should_behave_like "Indirection Delegator" - it_should_behave_like "Delegation Authorizer" - it "should return the result of the save" do @terminus.stubs(:save).returns "foo" @indirection.save(@instance).should == "foo" diff --git a/spec/unit/indirector/inventory/yaml_spec.rb b/spec/unit/indirector/inventory/yaml_spec.rb new file mode 100644 index 000000000..9f0c54353 --- /dev/null +++ b/spec/unit/indirector/inventory/yaml_spec.rb @@ -0,0 +1,221 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/node/inventory' +require 'puppet/indirector/inventory/yaml' +require 'puppet/indirector/request' + +describe Puppet::Node::Inventory::Yaml do + def assert_search_matches(matching, nonmatching, query) + request = Puppet::Indirector::Request.new(:inventory, :search, nil, query) + + Dir.stubs(:glob).returns(matching.keys + nonmatching.keys) + [matching, nonmatching].each do |examples| + examples.each do |key, value| + YAML.stubs(:load_file).with(key).returns value + end + end + Puppet::Node::Inventory::Yaml.new.search(request).should =~ matching.values.map {|facts| facts.name} + end + + it "should return node names that match the search query options" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '4'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "i386", 'processor_count' => '4', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), + "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), + }, + {'facts.architecture' => 'i386', 'facts.processor_count' => '4'} + ) + end + + it "should return empty array when no nodes match the search query options" do + assert_search_matches({}, { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '10'), + "/path/to/nonmatching1.yaml" => Puppet::Node::Facts.new("nonmatchingnode1", "architecture" => "powerpc", 'processor_count' => '5'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3", 'processor_count' => '4'), + }, + {'facts.processor_count.lt' => '4', 'facts.processor_count.gt' => '4'} + ) + end + + + it "should return node names that match the search query options with the greater than operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '10', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '4'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '3'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.gt' => '4'} + ) + end + + it "should return node names that match the search query options with the less than operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '30', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '50' ), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '100'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.lt' => '50'} + ) + end + + it "should return node names that match the search query options with the less than or equal to operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '5'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '100' ), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '5000'), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.le' => '50'} + ) + end + + it "should return node names that match the search query options with the greater than or equal to operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => "i386", 'processor_count' => '100'), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => "powerpc", 'processor_count' => '50', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "powerpc", 'processor_count' => '40'), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.processor_count.ge' => '50'} + ) + end + + it "should return node names that match the search query options with the not equal operator" do + assert_search_matches({ + '/path/to/matching.yaml' => Puppet::Node::Facts.new("matchingnode", "architecture" => 'arm' ), + '/path/to/matching1.yaml' => Puppet::Node::Facts.new("matchingnode1", "architecture" => 'powerpc', 'randomfact' => 'foo') + }, + { + "/path/to/nonmatching.yaml" => Puppet::Node::Facts.new("nonmatchingnode", "architecture" => "i386" ), + "/path/to/nonmatching2.yaml" => Puppet::Node::Facts.new("nonmatchingnode2", "architecture" => "i386", 'processor_count' => '9' ), + "/path/to/nonmatching3.yaml" => Puppet::Node::Facts.new("nonmatchingnode3" ), + }, + {'facts.architecture.ne' => 'i386'} + ) + end + + def apply_timestamp(facts, timestamp) + facts.timestamp = timestamp + facts + end + + it "should be able to query based on meta.timestamp.gt" do + assert_search_matches({ + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + }, + { + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + {'meta.timestamp.gt' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.le" do + assert_search_matches({ + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + }, + {'meta.timestamp.le' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.lt" do + assert_search_matches({ + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + {'meta.timestamp.lt' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.ge" do + assert_search_matches({ + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + {'meta.timestamp.ge' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.eq" do + assert_search_matches({ + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + {'meta.timestamp.eq' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp" do + assert_search_matches({ + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + { + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + {'meta.timestamp' => '2010-10-15'} + ) + end + + it "should be able to query based on meta.timestamp.ne" do + assert_search_matches({ + '/path/to/2010-11-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-01", {}), Time.parse("2010-11-01")), + '/path/to/2010-11-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-11-10", {}), Time.parse("2010-11-10")), + '/path/to/2010-10-01.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-01", {}), Time.parse("2010-10-01")), + '/path/to/2010-10-10.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-10", {}), Time.parse("2010-10-10")), + }, + { + '/path/to/2010-10-15.yaml' => apply_timestamp(Puppet::Node::Facts.new("2010-10-15", {}), Time.parse("2010-10-15")), + }, + {'meta.timestamp.ne' => '2010-10-15'} + ) + end +end diff --git a/spec/unit/indirector/node/ldap_spec.rb b/spec/unit/indirector/node/ldap_spec.rb index 042e7bd54..95ec12c80 100755 --- a/spec/unit/indirector/node/ldap_spec.rb +++ b/spec/unit/indirector/node/ldap_spec.rb @@ -311,7 +311,7 @@ describe Puppet::Node::Ldap do @options = {} @request = stub 'request', :key => "foo", :options => @options - Puppet::Node::Facts.stubs(:terminus_class).returns :yaml + Puppet::Node::Facts.indirection.stubs(:terminus_class).returns :yaml end it "should find all nodes if no arguments are provided" do diff --git a/spec/unit/indirector/report/yaml_spec.rb b/spec/unit/indirector/report/yaml_spec.rb new file mode 100644 index 000000000..610c9ae43 --- /dev/null +++ b/spec/unit/indirector/report/yaml_spec.rb @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet/transaction/report' +require 'puppet/indirector/report/yaml' + +describe Puppet::Transaction::Report::Yaml do + it "should be a subclass of the Yaml terminus" do + Puppet::Transaction::Report::Yaml.superclass.should equal(Puppet::Indirector::Yaml) + end + + it "should have documentation" do + Puppet::Transaction::Report::Yaml.doc.should_not be_nil + end + + it "should be registered with the report indirection" do + indirection = Puppet::Indirector::Indirection.instance(:report) + Puppet::Transaction::Report::Yaml.indirection.should equal(indirection) + end + + it "should have its name set to :yaml" do + Puppet::Transaction::Report::Yaml.name.should == :yaml + end + + it "should inconditionnally save/load from the --lastrunreport setting" do + indirection = stub 'indirection', :name => :my_yaml, :register_terminus_type => nil + Puppet::Indirector::Indirection.stubs(:instance).with(:my_yaml).returns(indirection) + store_class = Class.new(Puppet::Transaction::Report::Yaml) do + def self.to_s + "MyYaml::MyType" + end + end + store = store_class.new + + store.path(:me).should == Puppet[:lastrunreport] + end +end diff --git a/spec/unit/indirector_spec.rb b/spec/unit/indirector_spec.rb index fb21532ba..7c193a9aa 100755 --- a/spec/unit/indirector_spec.rb +++ b/spec/unit/indirector_spec.rb @@ -64,24 +64,6 @@ describe Puppet::Indirector, "when registering an indirection" do end end -describe "Delegated Indirection Method", :shared => true do - it "should delegate to the indirection" do - @indirection.expects(@method) - @thingie.send(@method, "me") - end - - it "should pass all of the passed arguments directly to the indirection instance" do - @indirection.expects(@method).with("me", :one => :two) - @thingie.send(@method, "me", :one => :two) - end - - it "should return the results of the delegation as its result" do - request = mock 'request' - @indirection.expects(@method).returns "yay" - @thingie.send(@method, "me").should == "yay" - end -end - describe Puppet::Indirector, "when redirecting a model" do before do @thingie = Class.new do @@ -98,59 +80,6 @@ describe Puppet::Indirector, "when redirecting a model" do @thingie.ancestors.should be_include(Puppet::Indirector::Envelope) end - describe "when finding instances via the model" do - before { @method = :find } - it_should_behave_like "Delegated Indirection Method" - end - - describe "when destroying instances via the model" do - before { @method = :destroy } - it_should_behave_like "Delegated Indirection Method" - end - - describe "when searching for instances via the model" do - before { @method = :search } - it_should_behave_like "Delegated Indirection Method" - end - - describe "when expiring instances via the model" do - before { @method = :expire } - it_should_behave_like "Delegated Indirection Method" - end - - # This is an instance method, so it behaves a bit differently. - describe "when saving instances via the model" do - before do - @instance = @thingie.new("me") - end - - it "should delegate to the indirection" do - @indirection.expects(:save) - @instance.save - end - - it "should pass the instance and an optional key to the indirection's :save method" do - @indirection.expects(:save).with("key", @instance) - @instance.save "key" - end - - it "should return the results of the delegation as its result" do - request = mock 'request' - @indirection.expects(:save).returns "yay" - @instance.save.should == "yay" - end - end - - it "should give the model the ability to set the indirection terminus class" do - @indirection.expects(:terminus_class=).with(:myterm) - @thingie.terminus_class = :myterm - end - - it "should give the model the ability to set the indirection cache class" do - @indirection.expects(:cache_class=).with(:mycache) - @thingie.cache_class = :mycache - end - after do @indirection.delete end diff --git a/spec/unit/network/http/api/v1_spec.rb b/spec/unit/network/http/api/v1_spec.rb index c593242c0..84b98ddaf 100644 --- a/spec/unit/network/http/api/v1_spec.rb +++ b/spec/unit/network/http/api/v1_spec.rb @@ -32,7 +32,7 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the first field of the URI as the environment" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).environment.should == Puppet::Node::Environment.new("env") + @tester.uri2indirection("GET", "/env/foo/bar", {})[3][:environment].should == "env" end it "should fail if the environment is not alphanumeric" do @@ -40,11 +40,11 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the environment from the URI even if one is specified in the parameters" do - @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"}).environment.should == Puppet::Node::Environment.new("env") + @tester.uri2indirection("GET", "/env/foo/bar", {:environment => "otherenv"})[3][:environment].should == "env" end it "should use the second field of the URI as the indirection name" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).indirection_name.should == :foo + @tester.uri2indirection("GET", "/env/foo/bar", {})[0].should == "foo" end it "should fail if the indirection name is not alphanumeric" do @@ -52,11 +52,11 @@ describe Puppet::Network::HTTP::API::V1 do end it "should use the remainder of the URI as the indirection key" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).key.should == "bar" + @tester.uri2indirection("GET", "/env/foo/bar", {})[2].should == "bar" end it "should support the indirection key being a /-separated file path" do - @tester.uri2indirection("GET", "/env/foo/bee/baz/bomb", {}).key.should == "bee/baz/bomb" + @tester.uri2indirection("GET", "/env/foo/bee/baz/bomb", {})[2].should == "bee/baz/bomb" end it "should fail if no indirection key is specified" do @@ -65,19 +65,31 @@ describe Puppet::Network::HTTP::API::V1 do end it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is singular" do - @tester.uri2indirection("GET", "/env/foo/bar", {}).method.should == :find + @tester.uri2indirection("GET", "/env/foo/bar", {})[1].should == :find end it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is plural" do - @tester.uri2indirection("GET", "/env/foos/bar", {}).method.should == :search + @tester.uri2indirection("GET", "/env/foos/bar", {})[1].should == :search + end + + it "should choose 'find' as the indirection method if the http method is a GET and the indirection name is facts" do + @tester.uri2indirection("GET", "/env/facts/bar", {})[1].should == :find + end + + it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is facts" do + @tester.uri2indirection("PUT", "/env/facts/bar", {})[1].should == :save + end + + it "should choose 'search' as the indirection method if the http method is a GET and the indirection name is inventory" do + @tester.uri2indirection("GET", "/env/inventory/search", {})[1].should == :search end it "should choose 'delete' as the indirection method if the http method is a DELETE and the indirection name is singular" do - @tester.uri2indirection("DELETE", "/env/foo/bar", {}).method.should == :destroy + @tester.uri2indirection("DELETE", "/env/foo/bar", {})[1].should == :destroy end it "should choose 'save' as the indirection method if the http method is a PUT and the indirection name is singular" do - @tester.uri2indirection("PUT", "/env/foo/bar", {}).method.should == :save + @tester.uri2indirection("PUT", "/env/foo/bar", {})[1].should == :save end it "should fail if an indirection method cannot be picked" do @@ -86,7 +98,8 @@ describe Puppet::Network::HTTP::API::V1 do it "should URI unescape the indirection key" do escaped = URI.escape("foo bar") - @tester.uri2indirection("GET", "/env/foo/#{escaped}", {}).key.should == "foo bar" + indirection_name, method, key, params = @tester.uri2indirection("GET", "/env/foo/#{escaped}", {}) + key.should == "foo bar" end end diff --git a/spec/unit/network/http/handler_spec.rb b/spec/unit/network/http/handler_spec.rb index 76a9c5530..e14b5739d 100755 --- a/spec/unit/network/http/handler_spec.rb +++ b/spec/unit/network/http/handler_spec.rb @@ -46,6 +46,8 @@ describe Puppet::Network::HTTP::Handler do @request.stubs(:[]).returns "foo" @response = stub('http response') @model_class = stub('indirected model class') + @indirection = stub('indirection') + @model_class.stubs(:indirection).returns(@indirection) @result = stub 'result', :render => "mytext" @@ -79,37 +81,22 @@ describe Puppet::Network::HTTP::Handler do @handler.process(@request, @response) end - it "should call the 'do' method associated with the indirection method" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request + it "should call the 'do' method and delegate authorization to the RestAuthorization layer" do + @handler.expects(:uri2indirection).returns(["facts", :mymethod, "key", {:node => "name"}]) - request.expects(:method).returns "mymethod" + @handler.expects(:do_mymethod).with("facts", "key", {:node => "name"}, @request, @response) - @handler.expects(:do_mymethod).with(request, @request, @response) - - @handler.process(@request, @response) - end - - it "should delegate authorization to the RestAuthorization layer" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request - - request.expects(:method).returns "mymethod" - - @handler.expects(:do_mymethod).with(request, @request, @response) - - @handler.expects(:check_authorization).with(request) + @handler.expects(:check_authorization).with("facts", :mymethod, "key", {:node => "name"}) @handler.process(@request, @response) end it "should return 403 if the request is not authorized" do - request = stub 'request' - @handler.expects(:uri2indirection).returns request + @handler.expects(:uri2indirection).returns(["facts", :mymethod, "key", {:node => "name"}]) @handler.expects(:do_mymethod).never - @handler.expects(:check_authorization).with(request).raises(Puppet::Network::AuthorizationError.new("forbindden")) + @handler.expects(:check_authorization).with("facts", :mymethod, "key", {:node => "name"}).raises(Puppet::Network::AuthorizationError.new("forbidden")) @handler.expects(:set_response).with { |response, body, status| status == 403 } @@ -117,7 +104,7 @@ describe Puppet::Network::HTTP::Handler do end it "should serialize a controller exception when an exception is thrown while finding the model instance" do - @handler.expects(:uri2indirection).returns stub("request", :method => :find) + @handler.expects(:uri2indirection).returns(["facts", :find, "key", {:node => "name"}]) @handler.expects(:do_find).raises(ArgumentError, "The exception") @handler.expects(:set_response).with { |response, body, status| body == "The exception" and status == 400 } @@ -141,9 +128,8 @@ describe Puppet::Network::HTTP::Handler do describe "when finding a model instance" do before do - @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "my_result", :model => @model_class - - @model_class.stubs(:find).returns @result + @indirection.stubs(:find).returns @result + Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" Puppet::Network::FormatHandler.stubs(:format).returns @format @@ -153,40 +139,37 @@ describe Puppet::Network::HTTP::Handler do end it "should use the indirection request to find the model class" do - @irequest.expects(:model).returns @model_class - - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use the escaped request key" do - @model_class.expects(:find).with do |key, args| + @indirection.expects(:find).with do |key, args| key == "my_result" end.returns @result - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) - @model_class.expects(:find).with do |key, args| + @indirection.expects(:find).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end.returns @result - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should set the content type to the first format specified in the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @handler.expects(:set_content_type).with(@response, @oneformat) - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should fail if no accept header is provided" do @handler.expects(:accept_header).with(@request).returns nil - lambda { @handler.do_find(@irequest, @request, @response) }.should raise_error(ArgumentError) + lambda { @handler.do_find("my_handler", "my_result", {}, @request, @response) }.should raise_error(ArgumentError) end it "should fail if the accept header does not contain a valid format" do @handler.expects(:accept_header).with(@request).returns "" - lambda { @handler.do_find(@irequest, @request, @response) }.should raise_error(RuntimeError) + lambda { @handler.do_find("my_handler", "my_result", {}, @request, @response) }.should raise_error(RuntimeError) end it "should not use an unsuitable format" do @@ -198,7 +181,7 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:set_content_type).with(@response, bar) # the suitable one - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should render the result using the first format specified in the accept header" do @@ -206,12 +189,12 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:accept_header).with(@request).returns "one,two" @result.expects(:render).with(@oneformat) - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should use the default status when a model find call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should return a serialized object when a model find call succeeds" do @@ -219,24 +202,24 @@ describe Puppet::Network::HTTP::Handler do @model_instance.expects(:render).returns "my_rendered_object" @handler.expects(:set_response).with { |response, body, status| body == "my_rendered_object" } - @model_class.stubs(:find).returns(@model_instance) - @handler.do_find(@irequest, @request, @response) + @indirection.stubs(:find).returns(@model_instance) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should return a 404 when no model instance can be found" do @model_class.stubs(:name).returns "my name" @handler.expects(:set_response).with { |response, body, status| status == 404 } - @model_class.stubs(:find).returns(nil) - @handler.do_find(@irequest, @request, @response) + @indirection.stubs(:find).returns(nil) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end it "should write a log message when no model instance can be found" do @model_class.stubs(:name).returns "my name" - @model_class.stubs(:find).returns(nil) + @indirection.stubs(:find).returns(nil) Puppet.expects(:info).with("Could not find my_handler for 'my_result'") - @handler.do_find(@irequest, @request, @response) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end @@ -245,21 +228,21 @@ describe Puppet::Network::HTTP::Handler do @handler.expects(:format_to_use).returns(@oneformat) @model_instance.expects(:render).with(@oneformat).returns "my_rendered_object" - @model_class.stubs(:find).returns(@model_instance) - @handler.do_find(@irequest, @request, @response) + @indirection.stubs(:find).returns(@model_instance) + @handler.do_find("my_handler", "my_result", {}, @request, @response) end end describe "when searching for model instances" do before do - @irequest = stub 'indirection_request', :method => :find, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @result1 = mock 'result1' @result2 = mock 'results' @result = [@result1, @result2] @model_class.stubs(:render_multiple).returns "my rendered instances" - @model_class.stubs(:search).returns(@result) + @indirection.stubs(:search).returns(@result) @format = stub 'format', :suitable? => true, :mime => "text/format", :name => "format" Puppet::Network::FormatHandler.stubs(:format).returns @format @@ -269,112 +252,109 @@ describe Puppet::Network::HTTP::Handler do end it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class - - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) - @model_class.expects(:search).with do |key, args| + @indirection.expects(:search).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end.returns @result - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should use the default status when a model search call succeeds" do - @model_class.stubs(:search).returns(@result) - @handler.do_search(@irequest, @request, @response) + @indirection.stubs(:search).returns(@result) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should set the content type to the first format returned by the accept header" do @handler.expects(:accept_header).with(@request).returns "one,two" @handler.expects(:set_content_type).with(@response, @oneformat) - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should return a list of serialized objects when a model search call succeeds" do @handler.expects(:accept_header).with(@request).returns "one,two" - @model_class.stubs(:search).returns(@result) + @indirection.stubs(:search).returns(@result) @model_class.expects(:render_multiple).with(@oneformat, @result).returns "my rendered instances" @handler.expects(:set_response).with { |response, data| data == "my rendered instances" } - @handler.do_search(@irequest, @request, @response) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end - it "should return a 404 when searching returns an empty array" do - @model_class.stubs(:name).returns "my name" - @handler.expects(:set_response).with { |response, body, status| status == 404 } - @model_class.stubs(:search).returns([]) - @handler.do_search(@irequest, @request, @response) + it "should return [] when searching returns an empty array" do + @handler.expects(:accept_header).with(@request).returns "one,two" + @indirection.stubs(:search).returns([]) + @model_class.expects(:render_multiple).with(@oneformat, []).returns "[]" + + + @handler.expects(:set_response).with { |response, data| data == "[]" } + @handler.do_search("my_handler", "my_result", {}, @request, @response) end it "should return a 404 when searching returns nil" do @model_class.stubs(:name).returns "my name" @handler.expects(:set_response).with { |response, body, status| status == 404 } - @model_class.stubs(:search).returns([]) - @handler.do_search(@irequest, @request, @response) + @indirection.stubs(:search).returns(nil) + @handler.do_search("my_handler", "my_result", {}, @request, @response) end end describe "when destroying a model instance" do before do - @irequest = stub 'indirection_request', :method => :destroy, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + Puppet::Indirector::Indirection.expects(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @result = stub 'result', :render => "the result" - @model_class.stubs(:destroy).returns @result + @indirection.stubs(:destroy).returns @result end it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class - - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end it "should use the escaped request key to destroy the instance in the model" do - @irequest.expects(:key).returns "foo bar" - @model_class.expects(:destroy).with do |key, args| + @indirection.expects(:destroy).with do |key, args| key == "foo bar" end - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "foo bar", {}, @request, @response) end it "should use a common method for determining the request parameters" do - @irequest.stubs(:to_hash).returns(:foo => :baz, :bar => :xyzzy) - @model_class.expects(:destroy).with do |key, args| + @indirection.expects(:destroy).with do |key, args| args[:foo] == :baz and args[:bar] == :xyzzy end - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {:foo => :baz, :bar => :xyzzy}, @request, @response) end it "should use the default status code a model destroy call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end it "should return a yaml-encoded result when a model destroy call succeeds" do @result = stub 'result', :to_yaml => "the result" - @model_class.expects(:destroy).returns(@result) + @indirection.expects(:destroy).returns(@result) @handler.expects(:set_response).with { |response, body, status| body == "the result" } - @handler.do_destroy(@irequest, @request, @response) + @handler.do_destroy("my_handler", "my_result", {}, @request, @response) end end describe "when saving a model instance" do before do - @irequest = stub 'indirection_request', :method => :save, :indirection_name => "my_handler", :to_hash => {}, :key => "key", :model => @model_class + Puppet::Indirector::Indirection.stubs(:instance).with(:my_handler).returns( stub "indirection", :model => @model_class ) @handler.stubs(:body).returns('my stuff') @handler.stubs(:content_type_header).returns("text/yaml") @result = stub 'result', :render => "the result" - @model_instance = stub('indirected model instance', :save => true) + @model_instance = stub('indirected model instance') @model_class.stubs(:convert_from).returns(@model_instance) + @indirection.stubs(:save) @format = stub 'format', :suitable? => true, :name => "format", :mime => "text/format" Puppet::Network::FormatHandler.stubs(:format).returns @format @@ -383,43 +363,41 @@ describe Puppet::Network::HTTP::Handler do end it "should use the indirection request to find the model" do - @irequest.expects(:model).returns @model_class - - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should use the 'body' hook to retrieve the body of the request" do @handler.expects(:body).returns "my body" @model_class.expects(:convert_from).with { |format, body| body == "my body" }.returns @model_instance - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should fail to save model if data is not specified" do @handler.stubs(:body).returns('') - lambda { @handler.do_save(@irequest, @request, @response) }.should raise_error(ArgumentError) + lambda { @handler.do_save("my_handler", "my_result", {}, @request, @response) }.should raise_error(ArgumentError) end it "should use a common method for determining the request parameters" do - @model_instance.expects(:save).with('key').once - @handler.do_save(@irequest, @request, @response) + @indirection.expects(:save).with(@model_instance, 'key').once + @handler.do_save("my_handler", "key", {}, @request, @response) end it "should use the default status when a model save call succeeds" do @handler.expects(:set_response).with { |response, body, status| status.nil? } - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should return the yaml-serialized result when a model save call succeeds" do - @model_instance.stubs(:save).returns(@model_instance) + @indirection.stubs(:save).returns(@model_instance) @model_instance.expects(:to_yaml).returns('foo') - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should set the content to yaml" do @handler.expects(:set_content_type).with(@response, @yamlformat) - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end it "should use the content-type header to know the body format" do @@ -428,7 +406,7 @@ describe Puppet::Network::HTTP::Handler do @model_class.expects(:convert_from).with { |format, body| format == "format" }.returns @model_instance - @handler.do_save(@irequest, @request, @response) + @handler.do_save("my_handler", "my_result", {}, @request, @response) end end end diff --git a/spec/unit/network/http/rack/xmlrpc_spec.rb b/spec/unit/network/http/rack/xmlrpc_spec.rb index 63ba28bf2..870438f2c 100755 --- a/spec/unit/network/http/rack/xmlrpc_spec.rb +++ b/spec/unit/network/http/rack/xmlrpc_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../../spec_helper' +require 'puppet/network/handler' require 'puppet/network/http/rack' if Puppet.features.rack? require 'puppet/network/http/rack/xmlrpc' if Puppet.features.rack? diff --git a/spec/unit/network/http/rack_spec.rb b/spec/unit/network/http/rack_spec.rb index df42a1ffa..8be9ccb50 100755 --- a/spec/unit/network/http/rack_spec.rb +++ b/spec/unit/network/http/rack_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../spec_helper' +require 'puppet/network/handler' require 'puppet/network/http/rack' if Puppet.features.rack? describe "Puppet::Network::HTTP::Rack" do diff --git a/spec/unit/network/http/webrick_spec.rb b/spec/unit/network/http/webrick_spec.rb index 2a6ef2268..91a35435a 100755 --- a/spec/unit/network/http/webrick_spec.rb +++ b/spec/unit/network/http/webrick_spec.rb @@ -4,6 +4,7 @@ # Copyright (c) 2007. All rights reserved. require File.dirname(__FILE__) + '/../../../spec_helper' +require 'puppet/network/handler' require 'puppet/network/http' require 'puppet/network/http/webrick' @@ -281,7 +282,7 @@ describe Puppet::Network::HTTP::WEBrick do @cert = stub 'cert', :content => "mycert" @host = stub 'host', :key => @key, :certificate => @cert, :name => "yay", :ssl_store => "mystore" - Puppet::SSL::Certificate.stubs(:find).with('ca').returns @cert + Puppet::SSL::Certificate.indirection.stubs(:find).with('ca').returns @cert Puppet::SSL::Host.stubs(:localhost).returns @host end @@ -298,7 +299,7 @@ describe Puppet::Network::HTTP::WEBrick do end it "should fail if no CA certificate can be found" do - Puppet::SSL::Certificate.stubs(:find).with('ca').returns nil + Puppet::SSL::Certificate.indirection.stubs(:find).with('ca').returns nil lambda { @server.setup_ssl }.should raise_error(Puppet::Error) end diff --git a/spec/unit/network/rest_authconfig_spec.rb b/spec/unit/network/rest_authconfig_spec.rb index 06436e723..10dbb76f6 100755 --- a/spec/unit/network/rest_authconfig_spec.rb +++ b/spec/unit/network/rest_authconfig_spec.rb @@ -29,9 +29,6 @@ describe Puppet::Network::RestAuthConfig do @acl = stub_everything 'rights' @authconfig.rights = @acl - - @request = stub 'request', :indirection_name => "path", :key => "to/resource", :ip => "127.0.0.1", - :node => "me", :method => :save, :environment => :env, :authenticated => true end it "should use the puppet default rest authorization file" do @@ -40,16 +37,10 @@ describe Puppet::Network::RestAuthConfig do Puppet::Network::RestAuthConfig.new(nil, false) end - it "should read the config file when needed" do - @authconfig.expects(:read) - - @authconfig.allowed?(@request) - end - it "should ask for authorization to the ACL subsystem" do @acl.expects(:fail_on_deny).with("/path/to/resource", :node => "me", :ip => "127.0.0.1", :method => :save, :environment => :env, :authenticated => true) - @authconfig.allowed?(@request) + @authconfig.allowed?("path", :save, "to/resource", :ip => "127.0.0.1", :node => "me", :environment => :env, :authenticated => true) end describe "when defining an acl with mk_acl" do diff --git a/spec/unit/network/rest_authorization_spec.rb b/spec/unit/network/rest_authorization_spec.rb deleted file mode 100755 index 0cb0bcee9..000000000 --- a/spec/unit/network/rest_authorization_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../../spec_helper' - -require 'puppet/network/rest_authorization' - -class RestAuthorized - include Puppet::Network::RestAuthorization -end - - -describe Puppet::Network::RestAuthorization do - before :each do - @auth = RestAuthorized.new - @authconig = stub 'authconfig' - @auth.stubs(:authconfig).returns(@authconfig) - - @request = stub_everything 'request' - @request.stubs(:method).returns(:find) - @request.stubs(:node).returns("node") - @request.stubs(:ip).returns("ip") - end - - describe "when testing request authorization" do - it "should delegate to the current rest authconfig" do - @authconfig.expects(:allowed?).with(@request).returns(true) - - @auth.check_authorization(@request) - end - - it "should raise an AuthorizationError if authconfig raises an AuthorizationError" do - @authconfig.expects(:allowed?).with(@request).raises(Puppet::Network::AuthorizationError.new("forbidden")) - - lambda { @auth.check_authorization(@request) }.should raise_error(Puppet::Network::AuthorizationError) - end - - it "should not raise an AuthorizationError if request is allowed" do - @authconfig.expects(:allowed?).with(@request).returns(true) - - lambda { @auth.check_authorization(@request) }.should_not raise_error(Puppet::Network::AuthorizationError) - end - end -end diff --git a/spec/unit/network/xmlrpc/client_spec.rb b/spec/unit/network/xmlrpc/client_spec.rb index 0b9b2b095..8440d39fa 100755 --- a/spec/unit/network/xmlrpc/client_spec.rb +++ b/spec/unit/network/xmlrpc/client_spec.rb @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +require 'puppet/network/client' Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") } diff --git a/spec/unit/node/environment_spec.rb b/spec/unit/node/environment_spec.rb index 6edcce56c..be2980879 100755 --- a/spec/unit/node/environment_spec.rb +++ b/spec/unit/node/environment_spec.rb @@ -52,7 +52,7 @@ describe Puppet::Node::Environment do before do @env = Puppet::Node::Environment.new("dev") @collection = Puppet::Resource::TypeCollection.new(@env) - @collection.stubs(:perform_initial_import) + @env.stubs(:perform_initial_import).returns(Puppet::Parser::AST::Hostclass.new('')) Thread.current[:known_resource_types] = nil end @@ -66,9 +66,8 @@ describe Puppet::Node::Environment do end it "should perform the initial import when creating a new collection" do - @collection.expects(:perform_initial_import) - Puppet::Resource::TypeCollection.expects(:new).returns @collection - + @env = Puppet::Node::Environment.new("dev") + @env.expects(:perform_initial_import).returns(Puppet::Parser::AST::Hostclass.new('')) @env.known_resource_types end @@ -274,4 +273,56 @@ describe Puppet::Node::Environment do @helper.environment.name.should == :foo end end + + describe "when performing initial import" do + before do + @parser = stub 'parser', :file= => nil, :string => nil, :parse => nil + Puppet::Parser::Parser.stubs(:new).returns @parser + @env = Puppet::Node::Environment.new("env") + end + + it "should create a new parser instance" do + Puppet::Parser::Parser.expects(:new).returns @parser + @env.instance_eval { perform_initial_import } + end + + it "should set the parser's string to the 'code' setting and parse if code is available" do + Puppet.settings[:code] = "my code" + @parser.expects(:string=).with "my code" + @parser.expects(:parse) + @env.instance_eval { perform_initial_import } + end + + it "should set the parser's file to the 'manifest' setting and parse if no code is available and the manifest is available" do + File.stubs(:expand_path).with("/my/file").returns "/my/file" + File.expects(:exist?).with("/my/file").returns true + Puppet.settings[:manifest] = "/my/file" + @parser.expects(:file=).with "/my/file" + @parser.expects(:parse) + @env.instance_eval { perform_initial_import } + end + + it "should not attempt to load a manifest if none is present" do + File.stubs(:expand_path).with("/my/file").returns "/my/file" + File.expects(:exist?).with("/my/file").returns false + Puppet.settings[:manifest] = "/my/file" + @parser.expects(:file=).never + @parser.expects(:parse).never + @env.instance_eval { perform_initial_import } + end + + it "should fail helpfully if there is an error importing" do + File.stubs(:exist?).returns true + @parser.expects(:parse).raises ArgumentError + lambda { @env.instance_eval { perform_initial_import } }.should raise_error(Puppet::Error) + end + + it "should not do anything if the ignore_import settings is set" do + Puppet.settings[:ignoreimport] = true + @parser.expects(:string=).never + @parser.expects(:file=).never + @parser.expects(:parse).never + @env.instance_eval { perform_initial_import } + end + end end diff --git a/spec/unit/node/facts_spec.rb b/spec/unit/node/facts_spec.rb index 394db7913..de2cd554f 100755 --- a/spec/unit/node/facts_spec.rb +++ b/spec/unit/node/facts_spec.rb @@ -76,16 +76,10 @@ describe Puppet::Node::Facts, "when indirecting" do @facts = Puppet::Node::Facts.new("me", "one" => "two") end - it "should redirect to the specified fact store for retrieval" do - Puppet::Node::Facts.stubs(:indirection).returns(@indirection) - @indirection.expects(:find) - Puppet::Node::Facts.find(:my_facts) - end - it "should redirect to the specified fact store for storage" do Puppet::Node::Facts.stubs(:indirection).returns(@indirection) @indirection.expects(:save) - @facts.save + Puppet::Node::Facts.indirection.save(@facts) end describe "when the Puppet application is 'master'" do @@ -109,5 +103,29 @@ describe Puppet::Node::Facts, "when indirecting" do facts = Puppet::Node::Facts.new("me", "one" => "two", "three" => "four") facts.values[:_timestamp].should be_instance_of(Time) end + + describe "using pson" do + before :each do + @timestamp = Time.parse("Thu Oct 28 11:16:31 -0700 2010") + @expiration = Time.parse("Thu Oct 28 11:21:31 -0700 2010") + end + + it "should accept properly formatted pson" do + pson = %Q({"name": "foo", "expiration": "#{@expiration}", "timestamp": "#{@timestamp}", "values": {"a": "1", "b": "2", "c": "3"}}) + format = Puppet::Network::FormatHandler.format('pson') + facts = format.intern(Puppet::Node::Facts,pson) + facts.name.should == 'foo' + facts.expiration.should == @expiration + facts.values.should == {'a' => '1', 'b' => '2', 'c' => '3', :_timestamp => @timestamp} + end + + it "should generate properly formatted pson" do + Time.stubs(:now).returns(@timestamp) + facts = Puppet::Node::Facts.new("foo", {'a' => 1, 'b' => 2, 'c' => 3}) + facts.expiration = @expiration + pson = PSON.parse(facts.to_pson) + pson.should == {"name"=>"foo", "timestamp"=>@timestamp.to_s, "expiration"=>@expiration.to_s, "values"=>{"a"=>1, "b"=>2, "c"=>3}} + end + end end end diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index 36334ea05..725075cb3 100755 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -84,11 +84,11 @@ end describe Puppet::Node, "when merging facts" do before do @node = Puppet::Node.new("testnode") - Puppet::Node::Facts.stubs(:find).with(@node.name).returns(Puppet::Node::Facts.new(@node.name, "one" => "c", "two" => "b")) + Puppet::Node::Facts.indirection.stubs(:find).with(@node.name).returns(Puppet::Node::Facts.new(@node.name, "one" => "c", "two" => "b")) end it "should fail intelligently if it cannot find facts" do - Puppet::Node::Facts.expects(:find).with(@node.name).raises "foo" + Puppet::Node::Facts.indirection.expects(:find).with(@node.name).raises "foo" lambda { @node.fact_merge }.should raise_error(Puppet::Error) end @@ -128,13 +128,6 @@ describe Puppet::Node, "when merging facts" do end describe Puppet::Node, "when indirecting" do - it "should redirect to the indirection" do - @indirection = stub 'indirection', :name => :node - Puppet::Node.stubs(:indirection).returns(@indirection) - @indirection.expects(:find) - Puppet::Node.find(:my_node.to_s) - end - it "should default to the 'plain' node terminus" do Puppet::Node.indirection.terminus_class.should == :plain end diff --git a/spec/unit/parser/ast/astarray_spec.rb b/spec/unit/parser/ast/astarray_spec.rb index f79d6c533..8794848b6 100755 --- a/spec/unit/parser/ast/astarray_spec.rb +++ b/spec/unit/parser/ast/astarray_spec.rb @@ -23,43 +23,26 @@ describe Puppet::Parser::AST::ASTArray do operator.evaluate(@scope) end - it "should evaluate childrens of type ASTArray" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields(item1) - - item1.expects(:safeevaluate).with(@scope).returns(123) - - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [123] - end - - it "should flatten children coming from children ASTArray" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields([item1]) - - item1.expects(:safeevaluate).with(@scope).returns(123) - - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [123] + it "should not flatten children coming from children ASTArray" do + item = Puppet::Parser::AST::String.new :value => 'foo' + inner_array = Puppet::Parser::AST::ASTArray.new :children => [item, item] + operator = Puppet::Parser::AST::ASTArray.new :children => [inner_array, inner_array] + operator.evaluate(@scope).should == [['foo', 'foo'], ['foo', 'foo']] end it "should not flatten the results of children evaluation" do - item1 = stub "item1", :is_a? => true - item2 = stub "item2" - item2.stubs(:is_a?).with(Puppet::Parser::AST).returns(true) - item2.stubs(:instance_of?).with(Puppet::Parser::AST::ASTArray).returns(true) - item2.stubs(:each).yields([item1]) - - item1.expects(:safeevaluate).with(@scope).returns([123]) + item = Puppet::Parser::AST::String.new :value => 'foo' + item.stubs(:evaluate).returns(['foo']) + operator = Puppet::Parser::AST::ASTArray.new :children => [item, item] + operator.evaluate(@scope).should == [['foo'], ['foo']] + end - operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [[123]] + it "should discard nil results from children evaluation" do + item1 = Puppet::Parser::AST::String.new :value => 'foo' + item2 = Puppet::Parser::AST::String.new :value => 'foo' + item2.stubs(:evaluate).returns(nil) + operator = Puppet::Parser::AST::ASTArray.new :children => [item1, item2] + operator.evaluate(@scope).should == ['foo'] end it "should return a valid string with to_s" do diff --git a/spec/unit/parser/ast/definition_spec.rb b/spec/unit/parser/ast/definition_spec.rb new file mode 100644 index 000000000..b7b2c851c --- /dev/null +++ b/spec/unit/parser/ast/definition_spec.rb @@ -0,0 +1,22 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Definition do + it "should make its context available through an accessor" do + definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) + definition.context.should == {:line => 5} + end + + describe "when instantiated" do + it "should create a definition with the proper type, name, context, and module name" do + definition = Puppet::Parser::AST::Definition.new('foo', :line => 5) + instantiated_definitions = definition.instantiate('modname') + instantiated_definitions.length.should == 1 + instantiated_definitions[0].type.should == :definition + instantiated_definitions[0].name.should == 'foo' + instantiated_definitions[0].line.should == 5 + instantiated_definitions[0].module_name.should == 'modname' + end + end +end diff --git a/spec/unit/parser/ast/hostclass_spec.rb b/spec/unit/parser/ast/hostclass_spec.rb new file mode 100644 index 000000000..b22eba98b --- /dev/null +++ b/spec/unit/parser/ast/hostclass_spec.rb @@ -0,0 +1,73 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Hostclass do + def ast + Puppet::Parser::AST + end + + def newarray(*elems) + ast::ASTArray.new({}).push(*elems) + end + + it "should make its name and context available through accessors" do + hostclass = ast::Hostclass.new('foo', :line => 5) + hostclass.name.should == 'foo' + hostclass.context.should == {:line => 5} + end + + it "should make its code available through an accessor" do + code = newarray + hostclass = ast::Hostclass.new('foo', :code => code) + hostclass.code.should be_equal(code) + end + + describe "when instantiated" do + it "should create a class with the proper type, code, name, context, and module name" do + code = newarray + hostclass = ast::Hostclass.new('foo', :code => code, :line => 5) + instantiated_class = hostclass.instantiate('modname')[0] + instantiated_class.type.should == :hostclass + instantiated_class.name.should == 'foo' + instantiated_class.code.should be_equal(code) + instantiated_class.line.should == 5 + instantiated_class.module_name.should == 'modname' + end + + it "should instantiate all nested classes, defines, and nodes with the same module name." do + nested_objects = newarray(ast::Hostclass.new('foo::child1'), + ast::Definition.new('foo::child2'), + ast::Definition.new('child3')) + hostclass = ast::Hostclass.new('foo', :code => nested_objects) + instantiated_classes = hostclass.instantiate('modname') + instantiated_classes.length.should == 4 + instantiated_classes[0].name.should == 'foo' + instantiated_classes[1].name.should == 'foo::child1' + instantiated_classes[2].name.should == 'foo::child2' + instantiated_classes[3].name.should == 'child3' + instantiated_classes.each { |cls| cls.module_name.should == 'modname' } + end + + it "should handle a nested class that contains its own nested classes." do + foo_bar_baz = ast::Hostclass.new('foo::bar::baz') + foo_bar = ast::Hostclass.new('foo::bar', :code => newarray(foo_bar_baz)) + foo = ast::Hostclass.new('foo', :code => newarray(foo_bar)) + instantiated_classes = foo.instantiate('') + instantiated_classes.length.should == 3 + instantiated_classes[0].name.should == 'foo' + instantiated_classes[1].name.should == 'foo::bar' + instantiated_classes[2].name.should == 'foo::bar::baz' + end + + it "should skip nested elements that are not classes, definitions, or nodes." do + func = ast::Function.new(:name => 'biz', :arguments => newarray(ast::Name.new(:value => 'baz'))) + foo = ast::Hostclass.new('foo', :code => newarray(func)) + instantiated_classes = foo.instantiate('') + instantiated_classes.length.should == 1 + instantiated_classes[0].should be_a(Puppet::Resource::Type) + instantiated_classes[0].name.should == 'foo' + end + end +end + diff --git a/spec/unit/parser/ast/node_spec.rb b/spec/unit/parser/ast/node_spec.rb new file mode 100644 index 000000000..3e8017de0 --- /dev/null +++ b/spec/unit/parser/ast/node_spec.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Node do + describe "when instantiated" do + it "should make its names and context available through accessors" do + node = Puppet::Parser::AST::Node.new(['foo', 'bar'], :line => 5) + node.names.should == ['foo', 'bar'] + node.context.should == {:line => 5} + end + + it "should create a node with the proper type, name, context, and module name" do + node = Puppet::Parser::AST::Node.new(['foo'], :line => 5) + instantiated_nodes = node.instantiate('modname') + instantiated_nodes.length.should == 1 + instantiated_nodes[0].type.should == :node + instantiated_nodes[0].name.should == 'foo' + instantiated_nodes[0].line.should == 5 + instantiated_nodes[0].module_name.should == 'modname' + end + + it "should handle multiple names" do + node = Puppet::Parser::AST::Node.new(['foo', 'bar']) + instantiated_nodes = node.instantiate('modname') + instantiated_nodes.length.should == 2 + instantiated_nodes[0].name.should == 'foo' + instantiated_nodes[1].name.should == 'bar' + end + end +end diff --git a/spec/unit/parser/ast/resource_spec.rb b/spec/unit/parser/ast/resource_spec.rb index 721c31a8d..3f7fa229a 100755 --- a/spec/unit/parser/ast/resource_spec.rb +++ b/spec/unit/parser/ast/resource_spec.rb @@ -11,14 +11,15 @@ describe Puppet::Parser::AST::Resource do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @scope.stubs(:resource).returns(stub_everything) - @resource = ast::Resource.new(:title => @title, :type => "file", :parameters => ast::ASTArray.new(:children => []) ) + @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) + @resource = ast::Resource.new(:type => "file", :instances => ast::ASTArray.new(:children => [@instance])) @resource.stubs(:qualified_type).returns("Resource") end it "should evaluate all its parameters" do param = stub 'param' param.expects(:safeevaluate).with(@scope).returns Puppet::Parser::Resource::Param.new(:name => "myparam", :value => "myvalue", :source => stub("source")) - @resource.stubs(:parameters).returns [param] + @instance.stubs(:parameters).returns [param] @resource.evaluate(@scope) end @@ -35,7 +36,7 @@ describe Puppet::Parser::AST::Resource do array = Puppet::Parser::AST::ASTArray.new(:children => titles) - @resource.title = array + @instance.title = array result = @resource.evaluate(@scope).collect { |r| r.title } result.should be_include("one") result.should be_include("two") @@ -49,12 +50,19 @@ describe Puppet::Parser::AST::Resource do array = Puppet::Parser::AST::ASTArray.new(:children => titles) - @resource.title = array + @instance.title = array result = @resource.evaluate(@scope).collect { |r| r.title } result.should be_include("one") result.should be_include("two") end + it "should implicitly iterate over instances" do + new_title = Puppet::Parser::AST::String.new(:value => "other_title") + new_instance = ast::ResourceInstance.new(:title => new_title, :parameters => ast::ASTArray.new(:children => [])) + @resource.instances.push(new_instance) + @resource.evaluate(@scope).collect { |r| r.title }.should == ["mytitle", "other_title"] + end + it "should handover resources to the compiler" do titles = [] %w{one two}.each do |title| @@ -63,7 +71,7 @@ describe Puppet::Parser::AST::Resource do array = Puppet::Parser::AST::ASTArray.new(:children => titles) - @resource.title = array + @instance.title = array result = @resource.evaluate(@scope) result.each do |res| @@ -91,16 +99,19 @@ describe Puppet::Parser::AST::Resource do before do @scope = Puppet::Parser::Scope.new :compiler => Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @parser = Puppet::Parser::Parser.new(Puppet::Node::Environment.new) - @parser.newdefine "one" - @parser.newdefine "one::two" - @parser.newdefine "three" + ["one", "one::two", "three"].each do |name| + @parser.environment.known_resource_types.add(Puppet::Resource::Type.new(:definition, name, {})) + end @twoscope = @scope.newscope(:namespace => "one") @twoscope.resource = @scope.resource end def resource(type, params = nil) params ||= Puppet::Parser::AST::ASTArray.new(:children => []) - Puppet::Parser::AST::Resource.new(:type => type, :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) + instance = Puppet::Parser::AST::ResourceInstance.new( + :title => Puppet::Parser::AST::String.new(:value => "myresource"), :parameters => params) + Puppet::Parser::AST::Resource.new(:type => type, + :instances => Puppet::Parser::AST::ASTArray.new(:children => [instance])) end it "should be able to generate resources with fully qualified type information" do @@ -141,7 +152,8 @@ describe Puppet::Parser::AST::Resource do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new(:compiler => @compiler) @scope.stubs(:resource).returns(stub_everything) - @resource = ast::Resource.new(:title => @title, :type => "Class", :parameters => ast::ASTArray.new(:children => []) ) + @instance = ast::ResourceInstance.new(:title => @title, :parameters => ast::ASTArray.new(:children => [])) + @resource = ast::Resource.new(:type => "Class", :instances => ast::ASTArray.new(:children => [@instance])) @resource.stubs(:qualified_type).returns("Resource") @type = Puppet::Resource::Type.new(:hostclass, "classname") @compiler.known_resource_types.add(@type) diff --git a/spec/unit/parser/collector_spec.rb b/spec/unit/parser/collector_spec.rb index 15808d6ff..908cda63a 100755 --- a/spec/unit/parser/collector_spec.rb +++ b/spec/unit/parser/collector_spec.rb @@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' require 'puppet/parser/collector' describe Puppet::Parser::Collector, "when initializing" do diff --git a/spec/unit/parser/parser_spec.rb b/spec/unit/parser/parser_spec.rb index 07e2d220b..ab43194e9 100755 --- a/spec/unit/parser/parser_spec.rb +++ b/spec/unit/parser/parser_spec.rb @@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/../../spec_helper' describe Puppet::Parser do - ast = Puppet::Parser::AST + Puppet::Parser::AST before :each do @known_resource_types = Puppet::Resource::TypeCollection.new("development") @@ -64,35 +64,37 @@ describe Puppet::Parser do lambda { @parser.parse("$var += ") }.should raise_error end - it "should call ast::VarDef with append=true" do - ast::VarDef.expects(:new).with { |h| h[:append] == true } - @parser.parse("$var += 2") + it "should create ast::VarDef with append=true" do + vardef = @parser.parse("$var += 2").code[0] + vardef.should be_a(Puppet::Parser::AST::VarDef) + vardef.append.should == true end it "should work with arrays too" do - ast::VarDef.expects(:new).with { |h| h[:append] == true } - @parser.parse("$var += ['test']") + vardef = @parser.parse("$var += ['test']").code[0] + vardef.should be_a(Puppet::Parser::AST::VarDef) + vardef.append.should == true end end describe "when parsing 'if'" do it "not, it should create the correct ast objects" do - ast::Not.expects(:new).with { |h| h[:value].is_a?(ast::Boolean) } + Puppet::Parser::AST::Not.expects(:new).with { |h| h[:value].is_a?(Puppet::Parser::AST::Boolean) } @parser.parse("if ! true { $var = 1 }") end it "boolean operation, it should create the correct ast objects" do - ast::BooleanOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Boolean) and h[:lval].is_a?(ast::Boolean) and h[:operator]=="or" + Puppet::Parser::AST::BooleanOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Boolean) and h[:lval].is_a?(Puppet::Parser::AST::Boolean) and h[:operator]=="or" } @parser.parse("if true or true { $var = 1 }") end it "comparison operation, it should create the correct ast objects" do - ast::ComparisonOperator.expects(:new).with { - |h| h[:lval].is_a?(ast::Name) and h[:rval].is_a?(ast::Name) and h[:operator]=="<" + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="<" } @parser.parse("if 1 < 2 { $var = 1 }") @@ -103,13 +105,13 @@ describe Puppet::Parser do describe "when parsing if complex expressions" do it "should create a correct ast tree" do aststub = stub_everything 'ast' - ast::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]==">" + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]==">" }.returns(aststub) - ast::ComparisonOperator.expects(:new).with { - |h| h[:rval].is_a?(ast::Name) and h[:lval].is_a?(ast::Name) and h[:operator]=="==" + Puppet::Parser::AST::ComparisonOperator.expects(:new).with { + |h| h[:rval].is_a?(Puppet::Parser::AST::Name) and h[:lval].is_a?(Puppet::Parser::AST::Name) and h[:operator]=="==" }.returns(aststub) - ast::BooleanOperator.expects(:new).with { + Puppet::Parser::AST::BooleanOperator.expects(:new).with { |h| h[:rval]==aststub and h[:lval]==aststub and h[:operator]=="and" } @parser.parse("if (1 > 2) and (1 == 2) { $var = 1 }") @@ -132,9 +134,8 @@ describe Puppet::Parser do end it "should create an ast::ResourceReference" do - ast::Resource.stubs(:new) - ast::ResourceReference.expects(:new).with { |arg| - arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(ast::ASTArray) + Puppet::Parser::AST::ResourceReference.expects(:new).with { |arg| + arg[:line]==1 and arg[:type]=="File" and arg[:title].is_a?(Puppet::Parser::AST::ASTArray) } @parser.parse('exec { test: command => File["a","b"] }') end @@ -151,10 +152,14 @@ describe Puppet::Parser do end it "should create an ast::ResourceOverride" do - ast::ResourceOverride.expects(:new).with { |arg| - arg[:line]==1 and arg[:object].is_a?(ast::ResourceReference) and arg[:parameters].is_a?(ast::ResourceParam) - } - @parser.parse('Resource["title1","title2"] { param => value }') + #Puppet::Parser::AST::ResourceOverride.expects(:new).with { |arg| + # arg[:line]==1 and arg[:object].is_a?(Puppet::Parser::AST::ResourceReference) and arg[:parameters].is_a?(Puppet::Parser::AST::ResourceParam) + #} + ro = @parser.parse('Resource["title1","title2"] { param => value }').code[0] + ro.should be_a(Puppet::Parser::AST::ResourceOverride) + ro.line.should == 1 + ro.object.should be_a(Puppet::Parser::AST::ResourceReference) + ro.parameters[0].should be_a(Puppet::Parser::AST::ResourceParam) end end @@ -174,17 +179,17 @@ describe Puppet::Parser do end it "should create a nop node for empty branch" do - ast::Nop.expects(:new) + Puppet::Parser::AST::Nop.expects(:new) @parser.parse("if true { }") end it "should create a nop node for empty else branch" do - ast::Nop.expects(:new) + Puppet::Parser::AST::Nop.expects(:new) @parser.parse("if true { notice('test') } else { }") end it "should build a chain of 'ifs' if there's an 'elsif'" do - ast = @parser.parse(<<-PP) + lambda { @parser.parse(<<-PP) }.should_not raise_error if true { notice('test') } elsif true {} else { } PP end @@ -288,24 +293,6 @@ describe Puppet::Parser do end end - describe "when creating a node" do - before :each do - @lexer = stub 'lexer' - @lexer.stubs(:getcomment) - @parser.stubs(:lexer).returns(@lexer) - @node = stub_everything 'node' - @parser.stubs(:ast_context).returns({}) - @parser.stubs(:node).returns(nil) - - @nodename = stub 'nodename', :is_a? => false, :value => "foo" - @nodename.stubs(:is_a?).with(Puppet::Parser::AST::HostName).returns(true) - end - - it "should return an array of nodes" do - @parser.newnode(@nodename).should be_instance_of(Array) - end - end - describe "when retrieving a specific node" do it "should delegate to the known_resource_types node" do @known_resource_types.expects(:node).with("node") @@ -358,30 +345,28 @@ describe Puppet::Parser do @parser.stubs(:known_resource_types).returns @krt end - it "should create new classes" do - @parser.parse("class foobar {}") - @krt.hostclass("foobar").should be_instance_of(Puppet::Resource::Type) + it "should not create new classes" do + @parser.parse("class foobar {}").code[0].should be_a(Puppet::Parser::AST::Hostclass) + @krt.hostclass("foobar").should be_nil end it "should correctly set the parent class when one is provided" do - @parser.parse("class foobar inherits yayness {}") - @krt.hostclass("foobar").parent.should == "yayness" + @parser.parse("class foobar inherits yayness {}").code[0].instantiate('')[0].parent.should == "yayness" end it "should correctly set the parent class for multiple classes at a time" do - @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}") - @krt.hostclass("foobar").parent.should == "yayness" - @krt.hostclass("boo").parent.should == "bar" + statements = @parser.parse("class foobar inherits yayness {}\nclass boo inherits bar {}").code + statements[0].instantiate('')[0].parent.should == "yayness" + statements[1].instantiate('')[0].parent.should == "bar" end it "should define the code when some is provided" do - @parser.parse("class foobar { $var = val }") - @krt.hostclass("foobar").code.should_not be_nil + @parser.parse("class foobar { $var = val }").code[0].code.should_not be_nil end it "should define parameters when provided" do - @parser.parse("class foobar($biz,$baz) {}") - @krt.hostclass("foobar").arguments.should == {"biz" => nil, "baz" => nil} + foobar = @parser.parse("class foobar($biz,$baz) {}").code[0].instantiate('')[0] + foobar.arguments.should == {"biz" => nil, "baz" => nil} end end @@ -398,13 +383,37 @@ describe Puppet::Parser do end it "should correctly mark exported resources as exported" do - @parser.parse("@@file { '/file': }") - @krt.hostclass("").code[0].exported.should be_true + @parser.parse("@@file { '/file': }").code[0].exported.should be_true end it "should correctly mark virtual resources as virtual" do - @parser.parse("@file { '/file': }") - @krt.hostclass("").code[0].virtual.should be_true + @parser.parse("@file { '/file': }").code[0].virtual.should be_true + end + end + + describe "when parsing nodes" do + it "should be able to parse a node with a single name" do + node = @parser.parse("node foo { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 1 + node.names[0].value.should == "foo" + end + + it "should be able to parse a node with two names" do + node = @parser.parse("node foo, bar { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 2 + node.names[0].value.should == "foo" + node.names[1].value.should == "bar" + end + + it "should be able to parse a node with three names" do + node = @parser.parse("node foo, bar, baz { }").code[0] + node.should be_a Puppet::Parser::AST::Node + node.names.length.should == 3 + node.names[0].value.should == "foo" + node.names[1].value.should == "bar" + node.names[2].value.should == "baz" end end end diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 9895f446b..2e390a53b 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -29,8 +29,7 @@ describe Puppet::Parser::Scope do end it "should be able to retrieve its parent module name from the source of its parent type" do - @topscope.source = Puppet::Resource::Type.new(:hostclass, :foo) - @topscope.source.module_name = "foo" + @topscope.source = Puppet::Resource::Type.new(:hostclass, :foo, :module_name => "foo") @scope.parent_module_name.should == "foo" end diff --git a/spec/unit/parser/templatewrapper_spec.rb b/spec/unit/parser/templatewrapper_spec.rb index d4d1d1b8e..68d90a1cc 100755 --- a/spec/unit/parser/templatewrapper_spec.rb +++ b/spec/unit/parser/templatewrapper_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/parser/templatewrapper' describe Puppet::Parser::TemplateWrapper do before(:each) do diff --git a/spec/unit/parser/type_loader_spec.rb b/spec/unit/parser/type_loader_spec.rb index 02d543b02..cfa68871d 100644 --- a/spec/unit/parser/type_loader_spec.rb +++ b/spec/unit/parser/type_loader_spec.rb @@ -28,85 +28,20 @@ describe Puppet::Parser::TypeLoader do describe "when loading names from namespaces" do it "should do nothing if the name to import is an empty string" do @loader.expects(:name2files).never - @loader.load_until(["foo"], "") { |f| false }.should be_nil - end - - it "should turn the provided namespaces and name into a list of files" do - @loader.expects(:name2files).with(["foo"], "bar").returns [] - @loader.load_until(["foo"], "bar") { |f| false } + @loader.try_load_fqname(:hostclass, "") { |filename, modname| raise :should_not_occur }.should be_nil end it "should attempt to import each generated name" do - @loader.expects(:name2files).returns %w{foo bar} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.load_until(["foo"], "bar") { |f| false } - end - - it "should yield after each import" do - yielded = [] - @loader.expects(:name2files).returns %w{foo bar} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.load_until(["foo"], "bar") { |f| yielded << f; false } - yielded.should == %w{foo bar} - end - - it "should stop importing when the yielded block returns true" do - yielded = [] - @loader.expects(:name2files).returns %w{foo bar baz} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.expects(:import).with("baz",nil).never - @loader.load_until(["foo"], "bar") { |f| true if f == "bar" } - end - - it "should return the result of the block" do - yielded = [] - @loader.expects(:name2files).returns %w{foo bar baz} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.expects(:import).with("baz",nil).never - @loader.load_until(["foo"], "bar") { |f| 10 if f == "bar" }.should == 10 - end - - it "should return nil if the block never returns true" do - @loader.expects(:name2files).returns %w{foo bar} - @loader.expects(:import).with("foo",nil) - @loader.expects(:import).with("bar",nil) - @loader.load_until(["foo"], "bar") { |f| false }.should be_nil - end - - it "should set the module name on any created resource types" do - type = Puppet::Resource::Type.new(:hostclass, "mytype") - - Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{one}] - @loader.stubs(:parse_file) - @loader.load_until(["foo"], "one") { |f| type } - - type.module_name.should == "modname" - end - end - - describe "when mapping names to files" do - { - [["foo"], "::bar::baz"] => %w{bar/baz}, - [[""], "foo::bar"] => %w{foo foo/bar}, - [%w{foo}, "bar"] => %w{foo foo/bar bar}, - [%w{a b}, "bar"] => %w{a a/bar b b/bar bar}, - [%w{a::b::c}, "bar"] => %w{a a/b/c/bar bar}, - [%w{a::b}, "foo::bar"] => %w{a a/b/foo/bar foo/bar} - }.each do |inputs, outputs| - it "should produce #{outputs.inspect} from the #{inputs[0].inspect} namespace and #{inputs[1]} name" do - @loader.name2files(*inputs).should == outputs - end + @loader.expects(:import).with("foo/bar",nil).returns([]) + @loader.expects(:import).with("foo",nil).returns([]) + @loader.try_load_fqname(:hostclass, "foo::bar") { |f| false } end end describe "when importing" do before do Puppet::Parser::Files.stubs(:find_manifests).returns ["modname", %w{file}] - Puppet::Parser::Parser.any_instance.stubs(:parse) + Puppet::Parser::Parser.any_instance.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) Puppet::Parser::Parser.any_instance.stubs(:file=) end @@ -138,19 +73,19 @@ describe Puppet::Parser::TypeLoader do it "should parse each found file" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] - @loader.expects(:parse_file).with("/one") + @loader.expects(:parse_file).with("/one").returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile") end it "should make each file qualified before attempting to parse it" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{one}] - @loader.expects(:parse_file).with("/current/one") + @loader.expects(:parse_file).with("/current/one").returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile", "/current/file") end it "should not attempt to import files that have already been imported" do Puppet::Parser::Files.expects(:find_manifests).returns ["modname", %w{/one}] - Puppet::Parser::Parser.any_instance.expects(:parse).once + Puppet::Parser::Parser.any_instance.expects(:parse).once.returns(Puppet::Parser::AST::Hostclass.new('')) @loader.import("myfile") # This will fail if it tries to reimport the file. @@ -161,7 +96,7 @@ describe Puppet::Parser::TypeLoader do describe "when parsing a file" do before do @parser = Puppet::Parser::Parser.new(@loader.environment) - @parser.stubs(:parse) + @parser.stubs(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @parser.stubs(:file=) Puppet::Parser::Parser.stubs(:new).with(@loader.environment).returns @parser end @@ -173,7 +108,7 @@ describe Puppet::Parser::TypeLoader do it "should assign the parser its file and parse" do @parser.expects(:file=).with("/my/file") - @parser.expects(:parse) + @parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @loader.parse_file("/my/file") end end @@ -185,4 +120,15 @@ describe Puppet::Parser::TypeLoader do @loader.known_resource_types.hostclass("foo").should be_instance_of(Puppet::Resource::Type) end + + describe "when deciding where to look for files" do + { 'foo' => ['foo'], + 'foo::bar' => ['foo/bar', 'foo'], + 'foo::bar::baz' => ['foo/bar/baz', 'foo/bar', 'foo'] + }.each do |fqname, expected_paths| + it "should look for #{fqname.inspect} in #{expected_paths.inspect}" do + @loader.instance_eval { name2files(fqname) }.should == expected_paths + end + end + end end diff --git a/spec/unit/provider/augeas/augeas_spec.rb b/spec/unit/provider/augeas/augeas_spec.rb index 07b632083..0cedbdbc3 100644 --- a/spec/unit/provider/augeas/augeas_spec.rb +++ b/spec/unit/provider/augeas/augeas_spec.rb @@ -316,6 +316,30 @@ describe provider_class do provider.stubs(:get_augeas_version).returns("0.3.5") provider.need_to_run?.should == false end + + #Ticket 5211 testing + it "should return true when a size != the provided value" do + resource = stub("resource") + resource.stubs(:[]).returns(false).then.returns("match path size != 17").then.returns("") + provider = provider_class.new(resource) + augeas_stub = stub("augeas", :match => ["set", "of", "values"]) + augeas_stub.stubs("close") + provider.aug= augeas_stub + provider.stubs(:get_augeas_version).returns("0.3.5") + provider.need_to_run?.should == true + end + + #Ticket 5211 testing + it "should return false when a size doeas equal the provided value" do + resource = stub("resource") + resource.stubs(:[]).returns(false).then.returns("match path size != 3").then.returns("") + provider = provider_class.new(resource) + augeas_stub = stub("augeas", :match => ["set", "of", "values"]) + augeas_stub.stubs("close") + provider.aug= augeas_stub + provider.stubs(:get_augeas_version).returns("0.3.5") + provider.need_to_run?.should == false + end end describe "augeas execution integration" do diff --git a/spec/unit/provider/host/parsed_spec.rb b/spec/unit/provider/host/parsed_spec.rb new file mode 100644 index 000000000..239e3bd86 --- /dev/null +++ b/spec/unit/provider/host/parsed_spec.rb @@ -0,0 +1,196 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +require 'puppet_spec/files' +require 'puppettest/support/utils' +require 'puppettest/fileparsing' + +provider_class = Puppet::Type.type(:host).provider(:parsed) + +describe provider_class do + include PuppetSpec::Files + extend PuppetTest::Support::Utils + include PuppetTest::FileParsing + + before do + @host_class = Puppet::Type.type(:host) + @provider = @host_class.provider(:parsed) + @hostfile = tmpfile('hosts') + @provider.any_instance.stubs(:target).returns @hostfile + end + + after :each do + @provider.initvars + end + + def mkhost(args) + hostresource = Puppet::Type::Host.new(:name => args[:name]) + hostresource.stubs(:should).with(:target).returns @hostfile + + # Using setters of provider + host = @provider.new(hostresource) + args.each do |property,value| + host.send("#{property}=", value) + end + host + end + + def genhost(host) + @provider.stubs(:filetype).returns(Puppet::Util::FileType::FileTypeRam) + File.stubs(:chown) + File.stubs(:chmod) + Puppet::Util::SUIDManager.stubs(:asuser).yields + host.flush + @provider.target_object(@hostfile).read + end + + describe "when parsing a line with ip and hostname" do + + it "should parse an ipv4 from the first field" do + @provider.parse_line("127.0.0.1 localhost")[:ip].should == "127.0.0.1" + end + + it "should parse an ipv6 from the first field" do + @provider.parse_line("::1 localhost")[:ip].should == "::1" + end + + it "should parse the name from the second field" do + @provider.parse_line("::1 localhost")[:name].should == "localhost" + end + + it "should set an empty comment" do + @provider.parse_line("::1 localhost")[:comment].should == "" + end + + end + + describe "when parsing a line with ip, hostname and comment" do + before do + @testline = "127.0.0.1 localhost # A comment with a #-char" + end + + it "should parse the ip from the first field" do + @provider.parse_line(@testline)[:ip].should == "127.0.0.1" + end + + it "should parse the hostname from the second field" do + @provider.parse_line(@testline)[:name].should == "localhost" + end + + it "should parse the comment after the first '#' character" do + @provider.parse_line(@testline)[:comment].should == 'A comment with a #-char' + end + + end + + describe "when parsing a line with ip, hostname and aliases" do + + it "should parse alias from the third field" do + @provider.parse_line("127.0.0.1 localhost localhost.localdomain")[:host_aliases].should == ["localhost.localdomain"] + end + + it "should parse multiple aliases" do + @provider.parse_line("127.0.0.1 host alias1 alias2")[:host_aliases].should == ['alias1', 'alias2'] + @provider.parse_line("127.0.0.1 host alias1\talias2")[:host_aliases].should == ['alias1', 'alias2'] + @provider.parse_line("127.0.0.1 host alias1\talias2 alias3")[:host_aliases].should == ['alias1', 'alias2', 'alias3'] + end + + end + + describe "when parsing a line with ip, hostname, aliases and comment" do + + before do + # Just playing with a few different delimiters + @testline = "127.0.0.1\t host alias1\talias2 alias3 # A comment with a #-char" + end + + it "should parse the ip from the first field" do + @provider.parse_line(@testline)[:ip].should == "127.0.0.1" + end + + it "should parse the hostname from the second field" do + @provider.parse_line(@testline)[:name].should == "host" + end + + it "should parse all host_aliases from the third field" do + @provider.parse_line(@testline)[:host_aliases].should == ['alias1' ,'alias2', 'alias3'] + end + + it "should parse the comment after the first '#' character" do + @provider.parse_line(@testline)[:comment].should == 'A comment with a #-char' + end + + end + + describe "when operating on /etc/hosts like files" do + fakedata("data/providers/host/parsed","valid*").each do |file| + it "should be able to parse #{file}" do + fakedataparse(file) + end + end + + it "should be able to generate a simple hostfile entry" do + host = mkhost( + :name => 'localhost', + :ip => '127.0.0.1', + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost\n" + end + + it "should be able to generate an entry with one alias" do + host = mkhost( + :name => 'localhost.localdomain', + :ip => '127.0.0.1', + :host_aliases => ['localhost'], + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost.localdomain\tlocalhost\n" + end + + it "should be able to generate an entry with more than one alias" do + host = mkhost( + :name => 'host', + :ip => '192.0.0.1', + :host_aliases => [ 'a1','a2','a3','a4' ], + :ensure => :present + ) + genhost(host).should == "192.0.0.1\thost\ta1\ta2\ta3\ta4\n" + end + + it "should be able to generate a simple hostfile entry with comments" do + host = mkhost( + :name => 'localhost', + :ip => '127.0.0.1', + :comment => 'Bazinga!', + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost\t# Bazinga!\n" + end + + it "should be able to generate an entry with one alias and a comment" do + host = mkhost( + :name => 'localhost.localdomain', + :ip => '127.0.0.1', + :host_aliases => ['localhost'], + :comment => 'Bazinga!', + :ensure => :present + ) + genhost(host).should == "127.0.0.1\tlocalhost.localdomain\tlocalhost\t# Bazinga!\n" + end + + it "should be able to generate an entry with more than one alias and a comment" do + host = mkhost( + :name => 'host', + :ip => '192.0.0.1', + :host_aliases => [ 'a1','a2','a3','a4' ], + :comment => 'Bazinga!', + :ensure => :present + ) + genhost(host).should == "192.0.0.1\thost\ta1\ta2\ta3\ta4\t# Bazinga!\n" + end + + end + +end diff --git a/spec/unit/provider/package/yum_spec.rb b/spec/unit/provider/package/yum_spec.rb new file mode 100644 index 000000000..f6a99aa78 --- /dev/null +++ b/spec/unit/provider/package/yum_spec.rb @@ -0,0 +1,67 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider = Puppet::Type.type(:package).provider(:yum) + +describe provider do + before do + # Create a mock resource + @resource = stub 'resource' + @resource.stubs(:[]).with(:name).returns 'mypackage' + @provider = provider.new(@resource) + @provider.stubs(:resource).returns @resource + @provider.stubs(:yum).returns 'yum' + @provider.stubs(:rpm).returns 'rpm' + @provider.stubs(:get).with(:name).returns 'mypackage' + @provider.stubs(:get).with(:version).returns '1' + @provider.stubs(:get).with(:release).returns '1' + @provider.stubs(:get).with(:arch).returns 'i386' + end + # provider should repond to the following methods + [:install, :latest, :update, :purge].each do |method| + it "should have a(n) #{method}" do + @provider.should respond_to(method) + end + end + + describe 'when installing' do + it 'should call yum install for :installed' do + @resource.stubs(:should).with(:ensure).returns :installed + @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage') + @provider.install + end + it 'should use :install to update' do + @provider.expects(:install) + @provider.update + end + it 'should be able to set version' do + @resource.stubs(:should).with(:ensure).returns '1.2' + @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :install, 'mypackage-1.2') + @provider.stubs(:query).returns :ensure => '1.2' + @provider.install + end + it 'should be able to downgrade' do + @resource.stubs(:should).with(:ensure).returns '1.0' + @provider.expects(:yum).with('-d', '0', '-e', '0', '-y', :downgrade, 'mypackage-1.0') + @provider.stubs(:query).returns(:ensure => '1.2').then.returns(:ensure => '1.0') + @provider.install + end + end + + describe 'when uninstalling' do + it 'should use erase to purge' do + @provider.expects(:yum).with('-y', :erase, 'mypackage') + @provider.purge + end + it 'should use rpm to uninstall' do + @provider.expects(:rpm).with('-e', 'mypackage-1-1.i386') + @provider.uninstall + end + end + + it 'should be versionable' do + provider.should be_versionable + end +end + diff --git a/spec/unit/provider/service/upstart.rb b/spec/unit/provider/service/upstart.rb new file mode 100644 index 000000000..9fde9e67f --- /dev/null +++ b/spec/unit/provider/service/upstart.rb @@ -0,0 +1,49 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +provider_class = Puppet::Type.type(:service).provider(:upstart) + +describe provider_class do + describe "#instances" do + it "should be able to find all instances" do + processes = ["rc stop/waiting", "ssh start/running, process 712"] + provider_class.stubs(:execpipe).yields(processes) + provider_class.instances.map {|provider| provider.name}.should =~ ["rc","ssh"] + end + + it "should attach the interface name for network interfaces" do + processes = ["network-interface (eth0)"] + provider_class.stubs(:execpipe).yields(processes) + provider_class.instances.first.name.should == "network-interface INTERFACE=eth0" + end + end + + describe "#status" do + it "should allow the user to override the status command" do + resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart, :status => "/bin/foo") + provider = provider_class.new(resource) + + provider.expects(:ucommand).with { `true`; true } + provider.status.should == :running + end + + it "should use the default status command if none is specified" do + resource = Puppet::Type.type(:service).new(:name => "foo", :provider => :upstart) + provider = provider_class.new(resource) + + provider.expects(:status_exec).with(["foo"]).returns("foo start/running, process 1000") + Process::Status.any_instance.stubs(:exitstatus).returns(0) + provider.status.should == :running + end + + it "should properly handle services with 'start' in their name" do + resource = Puppet::Type.type(:service).new(:name => "foostartbar", :provider => :upstart) + provider = provider_class.new(resource) + + provider.expects(:status_exec).with(["foostartbar"]).returns("foostartbar stop/waiting") + Process::Status.any_instance.stubs(:exitstatus).returns(0) + provider.status.should == :stopped + end + end +end diff --git a/spec/unit/rails/param_value_spec.rb b/spec/unit/rails/param_value_spec.rb index d6dc7d57b..243456e89 100755 --- a/spec/unit/rails/param_value_spec.rb +++ b/spec/unit/rails/param_value_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' describe "Puppet::Rails::ParamValue" do confine "Cannot test without ActiveRecord" => Puppet.features.rails? diff --git a/spec/unit/rails/resource_spec.rb b/spec/unit/rails/resource_spec.rb index 73c7f7af4..6e23d2020 100755 --- a/spec/unit/rails/resource_spec.rb +++ b/spec/unit/rails/resource_spec.rb @@ -1,6 +1,7 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../spec_helper' +require 'puppet/rails' describe "Puppet::Rails::Resource" do confine "Cannot test without ActiveRecord" => Puppet.features.rails? diff --git a/spec/unit/resource/catalog_spec.rb b/spec/unit/resource/catalog_spec.rb index 2b6beb5e9..672bb8ffc 100755 --- a/spec/unit/resource/catalog_spec.rb +++ b/spec/unit/resource/catalog_spec.rb @@ -374,7 +374,7 @@ describe Puppet::Resource::Catalog, "when compiling" do @original.add_edge(@r1,@r2) @original.filter do |r| r == @r1 - end.edge(@r1,@r2).should be_empty + end.edge?(@r1,@r2).should_not be end end @@ -818,12 +818,6 @@ describe Puppet::Resource::Catalog, "when compiling" do Puppet::Util::Cacher.expire end - it "should redirect to the indirection for retrieval" do - Puppet::Resource::Catalog.stubs(:indirection).returns(@indirection) - @indirection.expects(:find) - Puppet::Resource::Catalog.find(:myconfig) - end - it "should use the value of the 'catalog_terminus' setting to determine its terminus class" do # Puppet only checks the terminus setting the first time you ask # so this returns the object to the clean state @@ -933,8 +927,8 @@ describe Puppet::Resource::Catalog, "when converting to pson" do @catalog.add_edge(one, two) @catalog.add_edge(two, three) - @catalog.edge(one, two ).expects(:to_pson_data_hash).returns "one_two_pson" - @catalog.edge(two, three).expects(:to_pson_data_hash).returns "two_three_pson" + @catalog.edges_between(one, two )[0].expects(:to_pson_data_hash).returns "one_two_pson" + @catalog.edges_between(two, three)[0].expects(:to_pson_data_hash).returns "two_three_pson" PSON.parse(@catalog.to_pson,:create_additions => false)['data']['edges'].sort.should == %w{one_two_pson two_three_pson}.sort end diff --git a/spec/unit/resource/type_collection_spec.rb b/spec/unit/resource/type_collection_spec.rb index 577aea42b..b8da3cf58 100644 --- a/spec/unit/resource/type_collection_spec.rb +++ b/spec/unit/resource/type_collection_spec.rb @@ -89,6 +89,34 @@ describe Puppet::Resource::TypeCollection do loader.node("node").should be_nil end + describe "when resolving namespaces" do + [ ['', '::foo', ['foo']], + ['a', '::foo', ['foo']], + ['a::b', '::foo', ['foo']], + [['a::b'], '::foo', ['foo']], + [['a::b', 'c'], '::foo', ['foo']], + [['A::B', 'C'], '::Foo', ['foo']], + ['', '', ['']], + ['a', '', ['']], + ['a::b', '', ['']], + [['a::b'], '', ['']], + [['a::b', 'c'], '', ['']], + [['A::B', 'C'], '', ['']], + ['', 'foo', ['foo']], + ['a', 'foo', ['a::foo', 'foo']], + ['a::b', 'foo', ['a::b::foo', 'a::foo', 'foo']], + ['A::B', 'Foo', ['a::b::foo', 'a::foo', 'foo']], + [['a::b'], 'foo', ['a::b::foo', 'a::foo', 'foo']], + [['a', 'b'], 'foo', ['a::foo', 'foo', 'b::foo']], + [['a::b', 'c::d'], 'foo', ['a::b::foo', 'a::foo', 'foo', 'c::d::foo', 'c::foo']], + [['a::b', 'a::c'], 'foo', ['a::b::foo', 'a::foo', 'foo', 'a::c::foo']], + ].each do |namespaces, name, expected_result| + it "should resolve #{name.inspect} in namespaces #{namespaces.inspect} correctly" do + @code.instance_eval { resolve_namespaces(namespaces, name) }.should == expected_result + end + end + end + describe "when looking up names" do before do @type = Puppet::Resource::Type.new(:hostclass, "ns::klass") @@ -107,29 +135,32 @@ describe Puppet::Resource::TypeCollection do describe "that need to be loaded" do it "should use the loader to load the files" do - @code.loader.expects(:load_until).with(["ns"], "klass") - @code.find_or_load(["ns"], "klass", :hostclass) + @code.loader.expects(:try_load_fqname).with(:hostclass, "ns::klass") + @code.loader.expects(:try_load_fqname).with(:hostclass, "klass") + @code.find_hostclass(["ns"], "klass") end it "should downcase the name and downcase and array-fy the namespaces before passing to the loader" do - @code.loader.expects(:load_until).with(["ns"], "klass") - @code.find_or_load("Ns", "Klass", :hostclass) + @code.loader.expects(:try_load_fqname).with(:hostclass, "ns::klass") + @code.loader.expects(:try_load_fqname).with(:hostclass, "klass") + @code.find_hostclass("Ns", "Klass") end - it "should attempt to find the type when the loader yields" do - @code.loader.expects(:load_until).yields - @code.expects(:find).with(["ns"], "klass", :hostclass).times(2).returns(false).then.returns(true) - @code.find_or_load("ns", "klass", :hostclass) + it "should use the class returned by the loader" do + @code.loader.expects(:try_load_fqname).returns(:klass) + @code.expects(:hostclass).with("ns::klass").returns(false) + @code.find_hostclass("ns", "klass").should == :klass end - it "should return the result of 'load_until'" do - @code.loader.expects(:load_until).returns "foo" - @code.find_or_load("Ns", "Klass", :hostclass).should == "foo" + it "should return nil if the name isn't found" do + @code.stubs(:try_load_fqname).returns(nil) + @code.find_hostclass("Ns", "Klass").should be_nil end - it "should return nil if the name isn't found" do - @code.stubs(:load_until).returns(nil) - @code.find_or_load("Ns", "Klass", :hostclass).should be_nil + it "already-loaded names at broader scopes should not shadow autoloaded names" do + @code.add Puppet::Resource::Type.new(:hostclass, "bar") + @code.loader.expects(:try_load_fqname).with(:hostclass, "foo::bar").returns(:foobar) + @code.find_hostclass("foo", "bar").should == :foobar end end end @@ -195,68 +226,68 @@ describe Puppet::Resource::TypeCollection do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance - loader.find("namespace", "::foo::bar", :hostclass).should equal(instance) + loader.find_hostclass("namespace", "::foo::bar").should equal(instance) end it "should return nil if the instance name is fully qualified and no such instance exists" do loader = Puppet::Resource::TypeCollection.new("env") - loader.find("namespace", "::foo::bar", :hostclass).should be_nil + loader.find_hostclass("namespace", "::foo::bar").should be_nil end it "should be able to find classes in the base namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo") loader.add instance - loader.find("", "foo", :hostclass).should equal(instance) + loader.find_hostclass("", "foo").should equal(instance) end it "should return the partially qualified object if it exists in a provided namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo", "bar::baz", :hostclass).should equal(instance) + loader.find_hostclass("foo", "bar::baz").should equal(instance) end it "should be able to find partially qualified objects in any of the provided namespaces" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find(["nons", "foo", "otherns"], "bar::baz", :hostclass).should equal(instance) + loader.find_hostclass(["nons", "foo", "otherns"], "bar::baz").should equal(instance) end it "should return the unqualified object if it exists in a provided namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance - loader.find("foo", "bar", :hostclass).should equal(instance) + loader.find_hostclass("foo", "bar").should equal(instance) end it "should return the unqualified object if it exists in the parent namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar") loader.add instance - loader.find("foo::bar::baz", "bar", :hostclass).should equal(instance) + loader.find_hostclass("foo::bar::baz", "bar").should equal(instance) end it "should should return the partially qualified object if it exists in the parent namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo::bar", "bar::baz", :hostclass).should equal(instance) + loader.find_hostclass("foo::bar", "bar::baz").should equal(instance) end it "should return the qualified object if it exists in the root namespace" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo::bar", "foo::bar::baz", :hostclass).should equal(instance) + loader.find_hostclass("foo::bar", "foo::bar::baz").should equal(instance) end it "should return nil if the object cannot be found" do loader = Puppet::Resource::TypeCollection.new("env") instance = Puppet::Resource::Type.new(:hostclass, "foo::bar::baz") loader.add instance - loader.find("foo::bar", "eh", :hostclass).should be_nil + loader.find_hostclass("foo::bar", "eh").should be_nil end describe "when topscope has a class that has the same name as a local class" do @@ -268,11 +299,11 @@ describe Puppet::Resource::TypeCollection do end it "should favor the local class, if the name is unqualified" do - @loader.find("foo", "bar", :hostclass).name.should == 'foo::bar' + @loader.find_hostclass("foo", "bar").name.should == 'foo::bar' end it "should only look in the topclass, if the name is qualified" do - @loader.find("foo", "::bar", :hostclass).name.should == 'bar' + @loader.find_hostclass("foo", "::bar").name.should == 'bar' end end @@ -281,15 +312,16 @@ describe Puppet::Resource::TypeCollection do @loader = Puppet::Resource::TypeCollection.new("env") @loader.add Puppet::Resource::Type.new(:hostclass, "foo::bar") - @loader.find("foo", "::bar", :hostclass).should == nil + @loader.find_hostclass("foo", "::bar").should == nil end end - it "should use the generic 'find' method with an empty namespace to find nodes" do + it "should be able to find nodes" do + node = Puppet::Resource::Type.new(:node, "bar") loader = Puppet::Resource::TypeCollection.new("env") - loader.expects(:find).with("", "bar", :node) - loader.find_node(stub("ignored"), "bar") + loader.add(node) + loader.find_node(stub("ignored"), "bar").should == node end it "should use the 'find_or_load' method to find hostclasses" do @@ -384,58 +416,6 @@ describe Puppet::Resource::TypeCollection do end end - describe "when performing initial import" do - before do - @parser = stub 'parser', :file= => nil, :string => nil, :parse => nil - Puppet::Parser::Parser.stubs(:new).returns @parser - @code = Puppet::Resource::TypeCollection.new("env") - end - - it "should create a new parser instance" do - Puppet::Parser::Parser.expects(:new).returns @parser - @code.perform_initial_import - end - - it "should set the parser's string to the 'code' setting and parse if code is available" do - Puppet.settings[:code] = "my code" - @parser.expects(:string=).with "my code" - @parser.expects(:parse) - @code.perform_initial_import - end - - it "should set the parser's file to the 'manifest' setting and parse if no code is available and the manifest is available" do - File.stubs(:expand_path).with("/my/file").returns "/my/file" - File.expects(:exist?).with("/my/file").returns true - Puppet.settings[:manifest] = "/my/file" - @parser.expects(:file=).with "/my/file" - @parser.expects(:parse) - @code.perform_initial_import - end - - it "should not attempt to load a manifest if none is present" do - File.stubs(:expand_path).with("/my/file").returns "/my/file" - File.expects(:exist?).with("/my/file").returns false - Puppet.settings[:manifest] = "/my/file" - @parser.expects(:file=).never - @parser.expects(:parse).never - @code.perform_initial_import - end - - it "should fail helpfully if there is an error importing" do - File.stubs(:exist?).returns true - @parser.expects(:parse).raises ArgumentError - lambda { @code.perform_initial_import }.should raise_error(Puppet::Error) - end - - it "should not do anything if the ignore_import settings is set" do - Puppet.settings[:ignoreimport] = true - @parser.expects(:string=).never - @parser.expects(:file=).never - @parser.expects(:parse).never - @code.perform_initial_import - end - end - describe "when determining the configuration version" do before do @code = Puppet::Resource::TypeCollection.new("env") diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 7b240bb82..ef45712e6 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -322,7 +322,7 @@ describe Puppet::Resource::Type do end it "should set its module name in the scope if available" do - @type.module_name = "mymod" + @type.instance_eval { @module_name = "mymod" } @type.set_resource_parameters(@resource, @scope) @@ -531,8 +531,7 @@ describe Puppet::Resource::Type do @compiler.add_resource @scope, @parent_resource @type.resource_type_collection = @scope.known_resource_types - @type.resource_type_collection.stubs(:node).with("parent").returns(@parent_type) - @type.resource_type_collection.stubs(:node).with("Parent").returns(@parent_type) + @type.resource_type_collection.add(@parent_type) end it "should evaluate the parent's resource" do diff --git a/spec/unit/simple_graph_spec.rb b/spec/unit/simple_graph_spec.rb index 2ca8888c5..fa0bcb06a 100755 --- a/spec/unit/simple_graph_spec.rb +++ b/spec/unit/simple_graph_spec.rb @@ -31,12 +31,6 @@ describe Puppet::SimpleGraph do proc { @graph.to_dot_graph }.should_not raise_error end - it "should always put its edges first when printing yaml" do - @graph = Puppet::SimpleGraph.new - @graph.add_edge(:one, :two) - @graph.to_yaml_properties[0].should == "@edges" - end - describe "when managing vertices" do before do @graph = Puppet::SimpleGraph.new @@ -117,16 +111,31 @@ describe Puppet::SimpleGraph do @graph.edge?(:one, :two).should be_true end - it "should provide a method for retrieving an edge label" do - edge = Puppet::Relationship.new(:one, :two, :callback => :awesome) - @graph.add_edge(edge) - @graph.edge_label(:one, :two).should == {:callback => :awesome} - end + describe "when retrieving edges between two nodes" do + it "should handle the case of nodes not in the graph" do + @graph.edges_between(:one, :two).should == [] + end - it "should provide a method for retrieving an edge" do - edge = Puppet::Relationship.new(:one, :two) - @graph.add_edge(edge) - @graph.edge(:one, :two).should equal(edge) + it "should handle the case of nodes with no edges between them" do + @graph.add_vertex(:one) + @graph.add_vertex(:two) + @graph.edges_between(:one, :two).should == [] + end + + it "should handle the case of nodes connected by a single edge" do + edge = Puppet::Relationship.new(:one, :two) + @graph.add_edge(edge) + @graph.edges_between(:one, :two).length.should == 1 + @graph.edges_between(:one, :two)[0].should equal(edge) + end + + it "should handle the case of nodes connected by multiple edges" do + edge1 = Puppet::Relationship.new(:one, :two, :callback => :foo) + edge2 = Puppet::Relationship.new(:one, :two, :callback => :bar) + @graph.add_edge(edge1) + @graph.add_edge(edge2) + Set.new(@graph.edges_between(:one, :two)).should == Set.new([edge1, edge2]) + end end it "should add the edge source as a vertex if it is not already" do @@ -253,7 +262,7 @@ describe Puppet::SimpleGraph do it "should retain labels on edges" do @graph.add_edge(:one, :two, :callback => :awesome) - edge = @graph.reversal.edge(:two, :one) + edge = @graph.reversal.edges_between(:two, :one)[0] edge.label.should == {:callback => :awesome} end end @@ -522,14 +531,14 @@ describe Puppet::SimpleGraph do it "should not add labels to edges that have none" do @depgraph.add_edge(@two, @three) splice - @depgraph.edge_label("c", "i").should == {} + @depgraph.edges_between("c", "i")[0].label.should == {} end it "should copy labels over edges that have none" do @depgraph.add_edge("c", @three, {:callback => :refresh}) splice # And make sure the label got copied. - @depgraph.edge_label("c", "i").should == {:callback => :refresh} + @depgraph.edges_between("c", "i")[0].label.should == {:callback => :refresh} end it "should not replace a label with a nil label" do @@ -537,7 +546,7 @@ describe Puppet::SimpleGraph do @depgraph.add_edge(@middle, @three) @depgraph.add_edge("c", @three, {:callback => :refresh}) splice - @depgraph.edge_label("c", "i").should == {:callback => :refresh} + @depgraph.edges_between("c", "i")[0].label.should == {:callback => :refresh} end it "should copy labels to all created edges" do @@ -547,8 +556,207 @@ describe Puppet::SimpleGraph do @three.each do |child| edge = Puppet::Relationship.new("c", child) @depgraph.should be_edge(edge.source, edge.target) - @depgraph.edge_label(edge.source, edge.target).should == {:callback => :refresh} + @depgraph.edges_between(edge.source, edge.target)[0].label.should == {:callback => :refresh} + end + end + end + + it "should serialize to YAML using the old format by default" do + Puppet::SimpleGraph.use_new_yaml_format.should == false + end + + describe "(yaml tests)" do + def empty_graph(graph) + end + + def one_vertex_graph(graph) + graph.add_vertex(:a) + end + + def graph_without_edges(graph) + [:a, :b, :c].each { |x| graph.add_vertex(x) } + end + + def one_edge_graph(graph) + graph.add_edge(:a, :b) + end + + def many_edge_graph(graph) + graph.add_edge(:a, :b) + graph.add_edge(:a, :c) + graph.add_edge(:b, :d) + graph.add_edge(:c, :d) + end + + def labeled_edge_graph(graph) + graph.add_edge(:a, :b, :callback => :foo, :event => :bar) + end + + def overlapping_edge_graph(graph) + graph.add_edge(:a, :b, :callback => :foo, :event => :bar) + graph.add_edge(:a, :b, :callback => :biz, :event => :baz) + end + + def self.all_test_graphs + [:empty_graph, :one_vertex_graph, :graph_without_edges, :one_edge_graph, :many_edge_graph, :labeled_edge_graph, + :overlapping_edge_graph] + end + + def object_ids(enumerable) + # Return a sorted list of the object id's of the elements of an + # enumerable. + enumerable.collect { |x| x.object_id }.sort + end + + def graph_to_yaml(graph, which_format) + previous_use_new_yaml_format = Puppet::SimpleGraph.use_new_yaml_format + Puppet::SimpleGraph.use_new_yaml_format = (which_format == :new) + ZAML.dump(graph) + ensure + Puppet::SimpleGraph.use_new_yaml_format = previous_use_new_yaml_format + end + + # Test serialization of graph to YAML. + [:old, :new].each do |which_format| + all_test_graphs.each do |graph_to_test| + it "should be able to serialize #{graph_to_test} to YAML (#{which_format} format)" do + graph = Puppet::SimpleGraph.new + send(graph_to_test, graph) + yaml_form = graph_to_yaml(graph, which_format) + + # Hack the YAML so that objects in the Puppet namespace get + # changed to YAML::DomainType objects. This lets us inspect + # the serialized objects easily without invoking any + # yaml_initialize hooks. + yaml_form.gsub!('!ruby/object:Puppet::', '!hack/object:Puppet::') + serialized_object = YAML.load(yaml_form) + + # Check that the object contains instance variables @edges and + # @vertices only. @reversal is also permitted, but we don't + # check it, because it is going to be phased out. + serialized_object.type_id.should == 'object:Puppet::SimpleGraph' + serialized_object.value.keys.reject { |x| x == 'reversal' }.sort.should == ['edges', 'vertices'] + + # Check edges by forming a set of tuples (source, target, + # callback, event) based on the graph and the YAML and make sure + # they match. + edges = serialized_object.value['edges'] + edges.should be_a(Array) + expected_edge_tuples = graph.edges.collect { |edge| [edge.source, edge.target, edge.callback, edge.event] } + actual_edge_tuples = edges.collect do |edge| + edge.type_id.should == 'object:Puppet::Relationship' + %w{source target}.each { |x| edge.value.keys.should include(x) } + edge.value.keys.each { |x| ['source', 'target', 'callback', 'event'].should include(x) } + %w{source target callback event}.collect { |x| edge.value[x] } + end + Set.new(actual_edge_tuples).should == Set.new(expected_edge_tuples) + actual_edge_tuples.length.should == expected_edge_tuples.length + + # Check vertices one by one. + vertices = serialized_object.value['vertices'] + if which_format == :old + vertices.should be_a(Hash) + Set.new(vertices.keys).should == Set.new(graph.vertices) + vertices.each do |key, value| + value.type_id.should == 'object:Puppet::SimpleGraph::VertexWrapper' + value.value.keys.sort.should == %w{adjacencies vertex} + value.value['vertex'].should equal(key) + adjacencies = value.value['adjacencies'] + adjacencies.should be_a(Hash) + Set.new(adjacencies.keys).should == Set.new([:in, :out]) + [:in, :out].each do |direction| + adjacencies[direction].should be_a(Hash) + expected_adjacent_vertices = Set.new(graph.adjacent(key, :direction => direction, :type => :vertices)) + Set.new(adjacencies[direction].keys).should == expected_adjacent_vertices + adjacencies[direction].each do |adj_key, adj_value| + # Since we already checked edges, just check consistency + # with edges. + desired_source = direction == :in ? adj_key : key + desired_target = direction == :in ? key : adj_key + expected_edges = edges.select do |edge| + edge.value['source'] == desired_source && edge.value['target'] == desired_target + end + adj_value.should be_a(Set) + if object_ids(adj_value) != object_ids(expected_edges) + raise "For vertex #{key.inspect}, direction #{direction.inspect}: expected adjacencies #{expected_edges.inspect} but got #{adj_value.inspect}" + end + end + end + end + else + vertices.should be_a(Array) + Set.new(vertices).should == Set.new(graph.vertices) + vertices.length.should == graph.vertices.length + end + end + end + + # Test deserialization of graph from YAML. This presumes the + # correctness of serialization to YAML, which has already been + # tested. + all_test_graphs.each do |graph_to_test| + it "should be able to deserialize #{graph_to_test} from YAML (#{which_format} format)" do + reference_graph = Puppet::SimpleGraph.new + send(graph_to_test, reference_graph) + yaml_form = graph_to_yaml(reference_graph, which_format) + recovered_graph = YAML.load(yaml_form) + + # Test that the recovered vertices match the vertices in the + # reference graph. + expected_vertices = reference_graph.vertices.to_a + recovered_vertices = recovered_graph.vertices.to_a + Set.new(recovered_vertices).should == Set.new(expected_vertices) + recovered_vertices.length.should == expected_vertices.length + + # Test that the recovered edges match the edges in the + # reference graph. + expected_edge_tuples = reference_graph.edges.collect do |edge| + [edge.source, edge.target, edge.callback, edge.event] + end + recovered_edge_tuples = recovered_graph.edges.collect do |edge| + [edge.source, edge.target, edge.callback, edge.event] + end + Set.new(recovered_edge_tuples).should == Set.new(expected_edge_tuples) + recovered_edge_tuples.length.should == expected_edge_tuples.length + + # We ought to test that the recovered graph is self-consistent + # too. But we're not going to bother with that yet because + # the internal representation of the graph is about to change. + end + end + + it "should be able to serialize a graph where the vertices contain backreferences to the graph (#{which_format} format)" do + reference_graph = Puppet::SimpleGraph.new + vertex = Object.new + vertex.instance_eval { @graph = reference_graph } + reference_graph.add_edge(vertex, :other_vertex) + yaml_form = graph_to_yaml(reference_graph, which_format) + recovered_graph = YAML.load(yaml_form) + + recovered_graph.vertices.length.should == 2 + recovered_vertex = recovered_graph.vertices.reject { |x| x.is_a?(Symbol) }[0] + recovered_vertex.instance_eval { @graph }.should equal(recovered_graph) + recovered_graph.edges.length.should == 1 + recovered_edge = recovered_graph.edges[0] + recovered_edge.source.should equal(recovered_vertex) + recovered_edge.target.should == :other_vertex + end + end + + it "should serialize properly when used as a base class" do + class Puppet::TestDerivedClass < Puppet::SimpleGraph + attr_accessor :foo end + derived = Puppet::TestDerivedClass.new + derived.add_edge(:a, :b) + derived.foo = 1234 + recovered_derived = YAML.load(YAML.dump(derived)) + recovered_derived.class.should equal(Puppet::TestDerivedClass) + recovered_derived.edges.length.should == 1 + recovered_derived.edges[0].source.should == :a + recovered_derived.edges[0].target.should == :b + recovered_derived.vertices.length.should == 2 + recovered_derived.foo.should == 1234 end end end diff --git a/spec/unit/ssl/certificate_authority_spec.rb b/spec/unit/ssl/certificate_authority_spec.rb index 39fee3f0a..7198e33ad 100755 --- a/spec/unit/ssl/certificate_authority_spec.rb +++ b/spec/unit/ssl/certificate_authority_spec.rb @@ -138,18 +138,18 @@ describe Puppet::SSL::CertificateAuthority do it "should return any found CRL instance" do crl = mock 'crl' - Puppet::SSL::CertificateRevocationList.expects(:find).returns crl + Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns crl @ca.crl.should equal(crl) end it "should create, generate, and save a new CRL instance of no CRL can be found" do - crl = mock 'crl' - Puppet::SSL::CertificateRevocationList.expects(:find).returns nil + crl = Puppet::SSL::CertificateRevocationList.new("fakename") + Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns nil Puppet::SSL::CertificateRevocationList.expects(:new).returns crl crl.expects(:generate).with(@ca.host.certificate.content, @ca.host.key.content) - crl.expects(:save) + Puppet::SSL::CertificateRevocationList.indirection.expects(:save).with(crl) @ca.crl.should equal(crl) end @@ -235,12 +235,13 @@ describe Puppet::SSL::CertificateAuthority do @name = "myhost" @real_cert = stub 'realcert', :sign => nil - @cert = stub 'certificate', :content => @real_cert + @cert = Puppet::SSL::Certificate.new(@name) + @cert.content = @real_cert Puppet::SSL::Certificate.stubs(:new).returns @cert @cert.stubs(:content=) - @cert.stubs(:save) + Puppet::SSL::Certificate.indirection.stubs(:save) # Stub out the factory @factory = stub 'factory', :result => "my real cert" @@ -252,7 +253,7 @@ describe Puppet::SSL::CertificateAuthority do @inventory = stub 'inventory', :add => nil @ca.stubs(:inventory).returns @inventory - Puppet::SSL::CertificateRequest.stubs(:destroy) + Puppet::SSL::CertificateRequest.indirection.stubs(:destroy) end describe "and calculating the next certificate serial number" do @@ -295,7 +296,7 @@ describe Puppet::SSL::CertificateAuthority do end it "should not look up a certificate request for the host" do - Puppet::SSL::CertificateRequest.expects(:find).never + Puppet::SSL::CertificateRequest.indirection.expects(:find).never @ca.sign(@name, :ca, @request) end @@ -329,7 +330,7 @@ describe Puppet::SSL::CertificateAuthority do end it "should save the resulting certificate" do - @cert.expects(:save) + Puppet::SSL::Certificate.indirection.expects(:save).with(@cert) @ca.sign(@name, :ca, @request) end @@ -340,8 +341,8 @@ describe Puppet::SSL::CertificateAuthority do @serial = 10 @ca.stubs(:next_serial).returns @serial - Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request - @cert.stubs :save + Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request + Puppet::SSL::CertificateRequest.indirection.stubs :save end it "should use a certificate type of :server" do @@ -353,13 +354,13 @@ describe Puppet::SSL::CertificateAuthority do end it "should use look up a CSR for the host in the :ca_file terminus" do - Puppet::SSL::CertificateRequest.expects(:find).with(@name).returns @request + Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns @request @ca.sign(@name) end it "should fail if no CSR can be found for the host" do - Puppet::SSL::CertificateRequest.expects(:find).with(@name).returns nil + Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns nil lambda { @ca.sign(@name) }.should raise_error(ArgumentError) end @@ -390,12 +391,12 @@ describe Puppet::SSL::CertificateAuthority do end it "should save the resulting certificate" do - @cert.expects(:save) + Puppet::SSL::Certificate.indirection.stubs(:save).with(@cert) @ca.sign(@name) end it "should remove the host's certificate request" do - Puppet::SSL::CertificateRequest.expects(:destroy).with(@name) + Puppet::SSL::CertificateRequest.indirection.expects(:destroy).with(@name) @ca.sign(@name) end @@ -405,8 +406,8 @@ describe Puppet::SSL::CertificateAuthority do @serial = 10 @ca.stubs(:next_serial).returns @serial - Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request - @cert.stubs :save + Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request + Puppet::SSL::Certificate.indirection.stubs :save Puppet::SSL::Certificate.expects(:new).with(@name).returns @cert @ca.sign(@name) @@ -414,8 +415,8 @@ describe Puppet::SSL::CertificateAuthority do it "should return the certificate instance" do @ca.stubs(:next_serial).returns @serial - Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request - @cert.stubs :save + Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request + Puppet::SSL::Certificate.indirection.stubs :save @ca.sign(@name).should equal(@cert) end @@ -423,8 +424,8 @@ describe Puppet::SSL::CertificateAuthority do @ca.stubs(:next_serial).returns @serial @inventory.expects(:add).with(@cert) - Puppet::SSL::CertificateRequest.stubs(:find).with(@name).returns @request - @cert.stubs :save + Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request + Puppet::SSL::Certificate.indirection.stubs :save @ca.sign(@name) end @@ -436,7 +437,7 @@ describe Puppet::SSL::CertificateAuthority do it "should do nothing if autosign is disabled" do Puppet.settings.expects(:value).with(:autosign).returns 'false' - Puppet::SSL::CertificateRequest.expects(:search).never + Puppet::SSL::CertificateRequest.indirection.expects(:search).never @ca.autosign end @@ -444,7 +445,7 @@ describe Puppet::SSL::CertificateAuthority do Puppet.settings.expects(:value).with(:autosign).returns '/auto/sign' FileTest.expects(:exist?).with("/auto/sign").returns false - Puppet::SSL::CertificateRequest.expects(:search).never + Puppet::SSL::CertificateRequest.indirection.expects(:search).never @ca.autosign end @@ -454,7 +455,7 @@ describe Puppet::SSL::CertificateAuthority do FileTest.stubs(:exist?).with("/auto/sign").returns true File.stubs(:readlines).with("/auto/sign").returns ["one\n", "two\n"] - Puppet::SSL::CertificateRequest.stubs(:search).returns [] + Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [] @store = stub 'store', :allow => nil Puppet::Network::AuthStore.stubs(:new).returns @store @@ -495,13 +496,13 @@ describe Puppet::SSL::CertificateAuthority do it "should sign all CSRs whose hostname matches the autosign configuration" do csr1 = mock 'csr1' csr2 = mock 'csr2' - Puppet::SSL::CertificateRequest.stubs(:search).returns [csr1, csr2] + Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2] end it "should not sign CSRs whose hostname does not match the autosign configuration" do csr1 = mock 'csr1' csr2 = mock 'csr2' - Puppet::SSL::CertificateRequest.stubs(:search).returns [csr1, csr2] + Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2] end end end @@ -548,7 +549,7 @@ describe Puppet::SSL::CertificateAuthority do it "should be able to list waiting certificate requests" do req1 = stub 'req1', :name => "one" req2 = stub 'req2', :name => "two" - Puppet::SSL::CertificateRequest.expects(:search).with("*").returns [req1, req2] + Puppet::SSL::CertificateRequest.indirection.expects(:search).with("*").returns [req1, req2] @ca.waiting?.should == %w{one two} end @@ -566,19 +567,19 @@ describe Puppet::SSL::CertificateAuthority do it "should list certificates as the sorted list of all existing signed certificates" do cert1 = stub 'cert1', :name => "cert1" cert2 = stub 'cert2', :name => "cert2" - Puppet::SSL::Certificate.expects(:search).with("*").returns [cert1, cert2] + Puppet::SSL::Certificate.indirection.expects(:search).with("*").returns [cert1, cert2] @ca.list.should == %w{cert1 cert2} end describe "and printing certificates" do it "should return nil if the certificate cannot be found" do - Puppet::SSL::Certificate.expects(:find).with("myhost").returns nil + Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil @ca.print("myhost").should be_nil end it "should print certificates by calling :to_text on the host's certificate" do cert1 = stub 'cert1', :name => "cert1", :to_text => "mytext" - Puppet::SSL::Certificate.expects(:find).with("myhost").returns cert1 + Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns cert1 @ca.print("myhost").should == "mytext" end end @@ -586,19 +587,19 @@ describe Puppet::SSL::CertificateAuthority do describe "and fingerprinting certificates" do before :each do @cert = stub 'cert', :name => "cert", :fingerprint => "DIGEST" - Puppet::SSL::Certificate.stubs(:find).with("myhost").returns @cert - Puppet::SSL::CertificateRequest.stubs(:find).with("myhost") + Puppet::SSL::Certificate.indirection.stubs(:find).with("myhost").returns @cert + Puppet::SSL::CertificateRequest.indirection.stubs(:find).with("myhost") end it "should raise an error if the certificate or CSR cannot be found" do - Puppet::SSL::Certificate.expects(:find).with("myhost").returns nil - Puppet::SSL::CertificateRequest.expects(:find).with("myhost").returns nil + Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil + Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns nil lambda { @ca.fingerprint("myhost") }.should raise_error end it "should try to find a CSR if no certificate can be found" do - Puppet::SSL::Certificate.expects(:find).with("myhost").returns nil - Puppet::SSL::CertificateRequest.expects(:find).with("myhost").returns @cert + Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil + Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns @cert @cert.expects(:fingerprint) @ca.fingerprint("myhost") end @@ -623,7 +624,7 @@ describe Puppet::SSL::CertificateAuthority do Puppet.settings.stubs(:value).returns "crtstuff" @cert = stub 'cert', :content => "mycert" - Puppet::SSL::Certificate.stubs(:find).returns @cert + Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert @crl = stub('crl', :content => "mycrl") @@ -631,7 +632,7 @@ describe Puppet::SSL::CertificateAuthority do end it "should fail if the host's certificate cannot be found" do - Puppet::SSL::Certificate.expects(:find).with("me").returns(nil) + Puppet::SSL::Certificate.indirection.expects(:find).with("me").returns(nil) lambda { @ca.verify("me") }.should raise_error(ArgumentError) end @@ -694,7 +695,7 @@ describe Puppet::SSL::CertificateAuthority do @real_cert = stub 'real_cert', :serial => 15 @cert = stub 'cert', :content => @real_cert - Puppet::SSL::Certificate.stubs(:find).returns @cert + Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert end @@ -714,7 +715,7 @@ describe Puppet::SSL::CertificateAuthority do it "should get the serial number from the local certificate if it exists" do @ca.crl.expects(:revoke).with { |serial, key| serial == 15 } - Puppet::SSL::Certificate.expects(:find).with("host").returns @cert + Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns @cert @ca.revoke('host') end @@ -722,7 +723,7 @@ describe Puppet::SSL::CertificateAuthority do it "should get the serial number from inventory if no local certificate exists" do real_cert = stub 'real_cert', :serial => 15 cert = stub 'cert', :content => real_cert - Puppet::SSL::Certificate.expects(:find).with("host").returns nil + Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns nil @ca.inventory.expects(:serial).with("host").returns 16 @@ -739,13 +740,13 @@ describe Puppet::SSL::CertificateAuthority do before do @host = stub 'host', :generate_certificate_request => nil Puppet::SSL::Host.stubs(:new).returns @host - Puppet::SSL::Certificate.stubs(:find).returns nil + Puppet::SSL::Certificate.indirection.stubs(:find).returns nil @ca.stubs(:sign) end it "should fail if a certificate already exists for the host" do - Puppet::SSL::Certificate.expects(:find).with("him").returns "something" + Puppet::SSL::Certificate.indirection.expects(:find).with("him").returns "something" lambda { @ca.generate("him") }.should raise_error(ArgumentError) end diff --git a/spec/unit/ssl/certificate_request_spec.rb b/spec/unit/ssl/certificate_request_spec.rb index 437fc0556..fb4b5a134 100755 --- a/spec/unit/ssl/certificate_request_spec.rb +++ b/spec/unit/ssl/certificate_request_spec.rb @@ -187,22 +187,17 @@ describe Puppet::SSL::CertificateRequest do end describe "when a CSR is saved" do - it "should allow arguments" do - csr = Puppet::SSL::CertificateRequest.new("me") - csr.class.indirection.stubs(:save) - - lambda { csr.save :ipaddress => "foo" }.should_not raise_error - end - describe "and a CA is available" do it "should save the CSR and trigger autosigning" do ca = mock 'ca', :autosign Puppet::SSL::CertificateAuthority.expects(:instance).returns ca csr = Puppet::SSL::CertificateRequest.new("me") - Puppet::SSL::CertificateRequest.indirection.expects(:save).with(nil, csr) + terminus = mock 'terminus' + Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus) + terminus.expects(:save).with { |request| puts request.key.inspect; request.instance == csr && request.key == "me" } - csr.save + Puppet::SSL::CertificateRequest.indirection.save(csr) end end @@ -211,9 +206,11 @@ describe Puppet::SSL::CertificateRequest do Puppet::SSL::CertificateAuthority.expects(:instance).returns nil csr = Puppet::SSL::CertificateRequest.new("me") - Puppet::SSL::CertificateRequest.indirection.expects(:save).with(nil, csr) + terminus = mock 'terminus' + Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus) + terminus.expects(:save).with { |request| puts request.key.inspect; request.instance == csr && request.key == "me" } - csr.save + Puppet::SSL::CertificateRequest.indirection.save(csr) end end end diff --git a/spec/unit/ssl/certificate_revocation_list_spec.rb b/spec/unit/ssl/certificate_revocation_list_spec.rb index f9993d52e..3bf12fa0a 100755 --- a/spec/unit/ssl/certificate_revocation_list_spec.rb +++ b/spec/unit/ssl/certificate_revocation_list_spec.rb @@ -119,7 +119,7 @@ describe Puppet::SSL::CertificateRevocationList do @crl.generate(@cert, @key) @crl.content.stubs(:sign) - @crl.stubs :save + Puppet::SSL::CertificateRevocationList.indirection.stubs :save @key = mock 'key' end @@ -161,7 +161,7 @@ describe Puppet::SSL::CertificateRevocationList do end it "should save the CRL" do - @crl.expects :save + Puppet::SSL::CertificateRevocationList.indirection.expects(:save).with(@crl, nil) @crl.revoke(1, @key) end end diff --git a/spec/unit/ssl/host_spec.rb b/spec/unit/ssl/host_spec.rb index b2e43393c..77911091e 100755 --- a/spec/unit/ssl/host_spec.rb +++ b/spec/unit/ssl/host_spec.rb @@ -22,7 +22,7 @@ describe Puppet::SSL::Host do it "should retrieve its public key from its private key" do realkey = mock 'realkey' key = stub 'key', :content => realkey - Puppet::SSL::Key.stubs(:find).returns(key) + Puppet::SSL::Key.indirection.stubs(:find).returns(key) pubkey = mock 'public_key' realkey.expects(:public_key).returns pubkey @@ -142,8 +142,8 @@ describe Puppet::SSL::Host do describe "when specifying the CA location" do before do [Puppet::SSL::Key, Puppet::SSL::Certificate, Puppet::SSL::CertificateRequest, Puppet::SSL::CertificateRevocationList].each do |klass| - klass.stubs(:terminus_class=) - klass.stubs(:cache_class=) + klass.indirection.stubs(:terminus_class=) + klass.indirection.stubs(:cache_class=) end end @@ -169,23 +169,23 @@ describe Puppet::SSL::Host do describe "as 'local'" do it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do - Puppet::SSL::Certificate.expects(:cache_class=).with :file - Puppet::SSL::CertificateRequest.expects(:cache_class=).with :file - Puppet::SSL::CertificateRevocationList.expects(:cache_class=).with :file + Puppet::SSL::Certificate.indirection.expects(:cache_class=).with :file + Puppet::SSL::CertificateRequest.indirection.expects(:cache_class=).with :file + Puppet::SSL::CertificateRevocationList.indirection.expects(:cache_class=).with :file Puppet::SSL::Host.ca_location = :local end it "should set the terminus class for Key as :file" do - Puppet::SSL::Key.expects(:terminus_class=).with :file + Puppet::SSL::Key.indirection.expects(:terminus_class=).with :file Puppet::SSL::Host.ca_location = :local end it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :ca" do - Puppet::SSL::Certificate.expects(:terminus_class=).with :ca - Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :ca - Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :ca + Puppet::SSL::Certificate.indirection.expects(:terminus_class=).with :ca + Puppet::SSL::CertificateRequest.indirection.expects(:terminus_class=).with :ca + Puppet::SSL::CertificateRevocationList.indirection.expects(:terminus_class=).with :ca Puppet::SSL::Host.ca_location = :local end @@ -193,23 +193,23 @@ describe Puppet::SSL::Host do describe "as 'remote'" do it "should set the cache class for Certificate, CertificateRevocationList, and CertificateRequest as :file" do - Puppet::SSL::Certificate.expects(:cache_class=).with :file - Puppet::SSL::CertificateRequest.expects(:cache_class=).with :file - Puppet::SSL::CertificateRevocationList.expects(:cache_class=).with :file + Puppet::SSL::Certificate.indirection.expects(:cache_class=).with :file + Puppet::SSL::CertificateRequest.indirection.expects(:cache_class=).with :file + Puppet::SSL::CertificateRevocationList.indirection.expects(:cache_class=).with :file Puppet::SSL::Host.ca_location = :remote end it "should set the terminus class for Key as :file" do - Puppet::SSL::Key.expects(:terminus_class=).with :file + Puppet::SSL::Key.indirection.expects(:terminus_class=).with :file Puppet::SSL::Host.ca_location = :remote end it "should set the terminus class for Certificate, CertificateRevocationList, and CertificateRequest as :rest" do - Puppet::SSL::Certificate.expects(:terminus_class=).with :rest - Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :rest - Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :rest + Puppet::SSL::Certificate.indirection.expects(:terminus_class=).with :rest + Puppet::SSL::CertificateRequest.indirection.expects(:terminus_class=).with :rest + Puppet::SSL::CertificateRevocationList.indirection.expects(:terminus_class=).with :rest Puppet::SSL::Host.ca_location = :remote end @@ -217,18 +217,18 @@ describe Puppet::SSL::Host do describe "as 'only'" do it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :ca" do - Puppet::SSL::Key.expects(:terminus_class=).with :ca - Puppet::SSL::Certificate.expects(:terminus_class=).with :ca - Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :ca - Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :ca + Puppet::SSL::Key.indirection.expects(:terminus_class=).with :ca + Puppet::SSL::Certificate.indirection.expects(:terminus_class=).with :ca + Puppet::SSL::CertificateRequest.indirection.expects(:terminus_class=).with :ca + Puppet::SSL::CertificateRevocationList.indirection.expects(:terminus_class=).with :ca Puppet::SSL::Host.ca_location = :only end it "should reset the cache class for Certificate, CertificateRevocationList, and CertificateRequest to nil" do - Puppet::SSL::Certificate.expects(:cache_class=).with nil - Puppet::SSL::CertificateRequest.expects(:cache_class=).with nil - Puppet::SSL::CertificateRevocationList.expects(:cache_class=).with nil + Puppet::SSL::Certificate.indirection.expects(:cache_class=).with nil + Puppet::SSL::CertificateRequest.indirection.expects(:cache_class=).with nil + Puppet::SSL::CertificateRevocationList.indirection.expects(:cache_class=).with nil Puppet::SSL::Host.ca_location = :only end @@ -236,10 +236,10 @@ describe Puppet::SSL::Host do describe "as 'none'" do it "should set the terminus class for Key, Certificate, CertificateRevocationList, and CertificateRequest as :file" do - Puppet::SSL::Key.expects(:terminus_class=).with :file - Puppet::SSL::Certificate.expects(:terminus_class=).with :file - Puppet::SSL::CertificateRequest.expects(:terminus_class=).with :file - Puppet::SSL::CertificateRevocationList.expects(:terminus_class=).with :file + Puppet::SSL::Key.indirection.expects(:terminus_class=).with :file + Puppet::SSL::Certificate.indirection.expects(:terminus_class=).with :file + Puppet::SSL::CertificateRequest.indirection.expects(:terminus_class=).with :file + Puppet::SSL::CertificateRevocationList.indirection.expects(:terminus_class=).with :file Puppet::SSL::Host.ca_location = :none end @@ -252,21 +252,21 @@ describe Puppet::SSL::Host do describe "when destroying a host's SSL files" do before do - Puppet::SSL::Key.stubs(:destroy).returns false - Puppet::SSL::Certificate.stubs(:destroy).returns false - Puppet::SSL::CertificateRequest.stubs(:destroy).returns false + Puppet::SSL::Key.indirection.stubs(:destroy).returns false + Puppet::SSL::Certificate.indirection.stubs(:destroy).returns false + Puppet::SSL::CertificateRequest.indirection.stubs(:destroy).returns false end it "should destroy its certificate, certificate request, and key" do - Puppet::SSL::Key.expects(:destroy).with("myhost") - Puppet::SSL::Certificate.expects(:destroy).with("myhost") - Puppet::SSL::CertificateRequest.expects(:destroy).with("myhost") + Puppet::SSL::Key.indirection.expects(:destroy).with("myhost") + Puppet::SSL::Certificate.indirection.expects(:destroy).with("myhost") + Puppet::SSL::CertificateRequest.indirection.expects(:destroy).with("myhost") Puppet::SSL::Host.destroy("myhost") end it "should return true if any of the classes returned true" do - Puppet::SSL::Certificate.expects(:destroy).with("myhost").returns true + Puppet::SSL::Certificate.indirection.expects(:destroy).with("myhost").returns true Puppet::SSL::Host.destroy("myhost").should be_true end @@ -301,16 +301,17 @@ describe Puppet::SSL::Host do describe "when managing its private key" do before do @realkey = "mykey" - @key = stub 'key', :content => @realkey + @key = Puppet::SSL::Key.new("mykey") + @key.content = @realkey end it "should return nil if the key is not set and cannot be found" do - Puppet::SSL::Key.expects(:find).with("myname").returns(nil) + Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(nil) @host.key.should be_nil end it "should find the key in the Key class and return the Puppet instance" do - Puppet::SSL::Key.expects(:find).with("myname").returns(@key) + Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(@key) @host.key.should equal(@key) end @@ -318,7 +319,7 @@ describe Puppet::SSL::Host do Puppet::SSL::Key.expects(:new).with("myname").returns(@key) @key.expects(:generate) - @key.expects(:save) + Puppet::SSL::Key.indirection.expects(:save) @host.generate_key.should be_true @host.key.should equal(@key) @@ -328,14 +329,14 @@ describe Puppet::SSL::Host do Puppet::SSL::Key.expects(:new).with("myname").returns(@key) @key.stubs(:generate) - @key.expects(:save).raises "eh" + Puppet::SSL::Key.indirection.expects(:save).raises "eh" lambda { @host.generate_key }.should raise_error @host.key.should be_nil end it "should return any previously found key without requerying" do - Puppet::SSL::Key.expects(:find).with("myname").returns(@key).once + Puppet::SSL::Key.indirection.expects(:find).with("myname").returns(@key).once @host.key.should equal(@key) @host.key.should equal(@key) end @@ -344,16 +345,17 @@ describe Puppet::SSL::Host do describe "when managing its certificate request" do before do @realrequest = "real request" - @request = stub 'request', :content => @realrequest + @request = Puppet::SSL::CertificateRequest.new("myname") + @request.content = @realrequest end it "should return nil if the key is not set and cannot be found" do - Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns(nil) + Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns(nil) @host.certificate_request.should be_nil end it "should find the request in the Key class and return it and return the Puppet SSL request" do - Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns @request + Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns @request @host.certificate_request.should equal(@request) end @@ -367,7 +369,7 @@ describe Puppet::SSL::Host do @host.expects(:generate_key).returns(key) @request.stubs(:generate) - @request.stubs(:save) + Puppet::SSL::CertificateRequest.indirection.stubs(:save) @host.generate_certificate_request end @@ -378,14 +380,14 @@ describe Puppet::SSL::Host do key = stub 'key', :public_key => mock("public_key"), :content => "mycontent" @host.stubs(:key).returns(key) @request.expects(:generate).with("mycontent") - @request.expects(:save) + Puppet::SSL::CertificateRequest.indirection.expects(:save).with(@request) @host.generate_certificate_request.should be_true @host.certificate_request.should equal(@request) end it "should return any previously found request without requerying" do - Puppet::SSL::CertificateRequest.expects(:find).with("myname").returns(@request).once + Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myname").returns(@request).once @host.certificate_request.should equal(@request) @host.certificate_request.should equal(@request) @@ -397,11 +399,14 @@ describe Puppet::SSL::Host do key = stub 'key', :public_key => mock("public_key"), :content => "mycontent" @host.stubs(:key).returns(key) @request.stubs(:generate) - @request.expects(:save).raises "eh" + @request.stubs(:name).returns("myname") + terminus = stub 'terminus' + Puppet::SSL::CertificateRequest.indirection.expects(:prepare).returns(terminus) + terminus.expects(:save).with { |req| req.instance == @request && req.key == "myname" }.raises "eh" lambda { @host.generate_certificate_request }.should raise_error - @host.certificate_request.should be_nil + @host.instance_eval { @certificate_request }.should be_nil end end @@ -415,36 +420,36 @@ describe Puppet::SSL::Host do end it "should find the CA certificate if it does not have a certificate" do - Puppet::SSL::Certificate.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") - Puppet::SSL::Certificate.stubs(:find).with("myname").returns @cert + Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") + Puppet::SSL::Certificate.indirection.stubs(:find).with("myname").returns @cert @host.certificate end it "should not find the CA certificate if it is the CA host" do @host.expects(:ca?).returns true - Puppet::SSL::Certificate.stubs(:find) - Puppet::SSL::Certificate.expects(:find).with(Puppet::SSL::CA_NAME).never + Puppet::SSL::Certificate.indirection.stubs(:find) + Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).never @host.certificate end it "should return nil if it cannot find a CA certificate" do - Puppet::SSL::Certificate.expects(:find).with(Puppet::SSL::CA_NAME).returns nil - Puppet::SSL::Certificate.expects(:find).with("myname").never + Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns nil + Puppet::SSL::Certificate.indirection.expects(:find).with("myname").never @host.certificate.should be_nil end it "should find the key if it does not have one" do - Puppet::SSL::Certificate.stubs(:find) + Puppet::SSL::Certificate.indirection.stubs(:find) @host.expects(:key).returns mock("key") @host.certificate end it "should generate the key if one cannot be found" do - Puppet::SSL::Certificate.stubs(:find) + Puppet::SSL::Certificate.indirection.stubs(:find) @host.expects(:key).returns nil @host.expects(:generate_key) @@ -453,8 +458,8 @@ describe Puppet::SSL::Host do end it "should find the certificate in the Certificate class and return the Puppet certificate instance" do - Puppet::SSL::Certificate.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") - Puppet::SSL::Certificate.expects(:find).with("myname").returns @cert + Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") + Puppet::SSL::Certificate.indirection.expects(:find).with("myname").returns @cert @host.certificate.should equal(@cert) end @@ -462,14 +467,14 @@ describe Puppet::SSL::Host do it "should fail if the found certificate does not match the private key" do @host.expects(:certificate_matches_key?).returns false - Puppet::SSL::Certificate.stubs(:find).returns @cert + Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert lambda { @host.certificate }.should raise_error(Puppet::Error) end it "should return any previously found certificate" do - Puppet::SSL::Certificate.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") - Puppet::SSL::Certificate.expects(:find).with("myname").returns(@cert).once + Puppet::SSL::Certificate.indirection.expects(:find).with(Puppet::SSL::CA_NAME).returns mock("cacert") + Puppet::SSL::Certificate.indirection.expects(:find).with("myname").returns(@cert).once @host.certificate.should equal(@cert) @host.certificate.should equal(@cert) @@ -482,30 +487,30 @@ describe Puppet::SSL::Host do describe "when listing certificate hosts" do it "should default to listing all clients with any file types" do - Puppet::SSL::Key.expects(:search).returns [] - Puppet::SSL::Certificate.expects(:search).returns [] - Puppet::SSL::CertificateRequest.expects(:search).returns [] + Puppet::SSL::Key.indirection.expects(:search).returns [] + Puppet::SSL::Certificate.indirection.expects(:search).returns [] + Puppet::SSL::CertificateRequest.indirection.expects(:search).returns [] Puppet::SSL::Host.search end it "should be able to list only clients with a key" do - Puppet::SSL::Key.expects(:search).returns [] - Puppet::SSL::Certificate.expects(:search).never - Puppet::SSL::CertificateRequest.expects(:search).never + Puppet::SSL::Key.indirection.expects(:search).returns [] + Puppet::SSL::Certificate.indirection.expects(:search).never + Puppet::SSL::CertificateRequest.indirection.expects(:search).never Puppet::SSL::Host.search :for => Puppet::SSL::Key end it "should be able to list only clients with a certificate" do - Puppet::SSL::Key.expects(:search).never - Puppet::SSL::Certificate.expects(:search).returns [] - Puppet::SSL::CertificateRequest.expects(:search).never + Puppet::SSL::Key.indirection.expects(:search).never + Puppet::SSL::Certificate.indirection.expects(:search).returns [] + Puppet::SSL::CertificateRequest.indirection.expects(:search).never Puppet::SSL::Host.search :for => Puppet::SSL::Certificate end it "should be able to list only clients with a certificate request" do - Puppet::SSL::Key.expects(:search).never - Puppet::SSL::Certificate.expects(:search).never - Puppet::SSL::CertificateRequest.expects(:search).returns [] + Puppet::SSL::Key.indirection.expects(:search).never + Puppet::SSL::Certificate.indirection.expects(:search).never + Puppet::SSL::CertificateRequest.indirection.expects(:search).returns [] Puppet::SSL::Host.search :for => Puppet::SSL::CertificateRequest end @@ -514,9 +519,9 @@ describe Puppet::SSL::Host do cert = stub 'cert', :name => "cert" csr = stub 'csr', :name => "csr" - Puppet::SSL::Key.expects(:search).returns [key] - Puppet::SSL::Certificate.expects(:search).returns [cert] - Puppet::SSL::CertificateRequest.expects(:search).returns [csr] + Puppet::SSL::Key.indirection.expects(:search).returns [key] + Puppet::SSL::Certificate.indirection.expects(:search).returns [cert] + Puppet::SSL::CertificateRequest.indirection.expects(:search).returns [csr] returned = [] %w{key cert csr}.each do |name| @@ -606,7 +611,7 @@ describe Puppet::SSL::Host do Puppet.settings.stubs(:value).with(:localcacert).returns "ssl_host_testing" - Puppet::SSL::CertificateRevocationList.stubs(:find).returns(nil) + Puppet::SSL::CertificateRevocationList.indirection.stubs(:find).returns(nil) end it "should accept a purpose" do @@ -628,7 +633,7 @@ describe Puppet::SSL::Host do describe "and a CRL is available" do before do @crl = stub 'crl', :content => "real_crl" - Puppet::SSL::CertificateRevocationList.stubs(:find).returns @crl + Puppet::SSL::CertificateRevocationList.indirection.stubs(:find).returns @crl Puppet.settings.stubs(:value).with(:certificate_revocation).returns true end diff --git a/spec/unit/ssl/inventory_spec.rb b/spec/unit/ssl/inventory_spec.rb index a57d6fafc..008fece0b 100755 --- a/spec/unit/ssl/inventory_spec.rb +++ b/spec/unit/ssl/inventory_spec.rb @@ -40,7 +40,7 @@ describe Puppet::SSL::Inventory do Puppet.settings.stubs(:write) FileTest.stubs(:exist?).with("/inven/tory").returns false - Puppet::SSL::Certificate.stubs(:search).returns [] + Puppet::SSL::Certificate.indirection.stubs(:search).returns [] end it "should log that it is building a new inventory file" do @@ -67,7 +67,7 @@ describe Puppet::SSL::Inventory do cert1 = mock 'cert1' cert2 = mock 'cert2' - Puppet::SSL::Certificate.expects(:search).with("*").returns [cert1, cert2] + Puppet::SSL::Certificate.indirection.expects(:search).with("*").returns [cert1, cert2] @class.any_instance.expects(:add).with(cert1) @class.any_instance.expects(:add).with(cert2) diff --git a/spec/unit/status_spec.rb b/spec/unit/status_spec.rb index 71bfa4a44..938bbdf84 100644 --- a/spec/unit/status_spec.rb +++ b/spec/unit/status_spec.rb @@ -4,8 +4,8 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Puppet::Status do it "should implement find" do - Puppet::Status.find( :default ).should be_is_a(Puppet::Status) - Puppet::Status.find( :default ).status["is_alive"].should == true + Puppet::Status.indirection.find( :default ).should be_is_a(Puppet::Status) + Puppet::Status.indirection.find( :default ).status["is_alive"].should == true end it "should default to is_alive is true" do diff --git a/spec/unit/transaction/report_spec.rb b/spec/unit/transaction/report_spec.rb index 7e0b0554b..1f1fdb080 100755 --- a/spec/unit/transaction/report_spec.rb +++ b/spec/unit/transaction/report_spec.rb @@ -53,20 +53,13 @@ describe Puppet::Transaction::Report do end describe "when using the indirector" do - it "should redirect :find to the indirection" do - @indirection = stub 'indirection', :name => :report - Puppet::Transaction::Report.stubs(:indirection).returns(@indirection) - @indirection.expects(:find) - Puppet::Transaction::Report.find(:report) - end - it "should redirect :save to the indirection" do Facter.stubs(:value).returns("eh") @indirection = stub 'indirection', :name => :report Puppet::Transaction::Report.stubs(:indirection).returns(@indirection) report = Puppet::Transaction::Report.new @indirection.expects(:save) - report.save + Puppet::Transaction::Report.indirection.save(report) end it "should default to the 'processor' terminus" do @@ -225,8 +218,19 @@ describe Puppet::Transaction::Report do @report.calculate_metrics end - %w{Changes Total Resources}.each do |main| - it "should include information on #{main} in the summary" do + %w{changes time resources events}.each do |main| + it "should include the key #{main} in the raw summary hash" do + @report.raw_summary.should be_key main + end + end + + it "should include the last run time in the raw summary hash" do + Time.stubs(:now).returns(Time.utc(2010,11,10,12,0,24)) + @report.raw_summary["time"]["last_run"].should == 1289390424 + end + + %w{Changes Total Resources Time Events}.each do |main| + it "should include information on #{main} in the textual summary" do @report.summary.should be_include(main) end end diff --git a/spec/unit/type/file/source_spec.rb b/spec/unit/type/file/source_spec.rb index a45a1f74e..b6833f77c 100755 --- a/spec/unit/type/file/source_spec.rb +++ b/spec/unit/type/file/source_spec.rb @@ -54,22 +54,22 @@ describe Puppet::Type.type(:file).attrclass(:source) do it "should collect its metadata using the Metadata class if it is not already set" do @source = source.new(:resource => @resource, :value => "/foo/bar") - Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns @metadata + Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns @metadata @source.metadata end it "should use the metadata from the first found source" do metadata = stub 'metadata', :source= => nil @source = source.new(:resource => @resource, :value => ["/foo/bar", "/fee/booz"]) - Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns nil - Puppet::FileServing::Metadata.expects(:find).with("/fee/booz").returns metadata + Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns nil + Puppet::FileServing::Metadata.indirection.expects(:find).with("/fee/booz").returns metadata @source.metadata.should equal(metadata) end it "should store the found source as the metadata's source" do metadata = mock 'metadata' @source = source.new(:resource => @resource, :value => "/foo/bar") - Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns metadata + Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns metadata metadata.expects(:source=).with("/foo/bar") @source.metadata @@ -77,7 +77,7 @@ describe Puppet::Type.type(:file).attrclass(:source) do it "should fail intelligently if an exception is encountered while querying for metadata" do @source = source.new(:resource => @resource, :value => "/foo/bar") - Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").raises RuntimeError + Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").raises RuntimeError @source.expects(:fail).raises ArgumentError lambda { @source.metadata }.should raise_error(ArgumentError) @@ -85,7 +85,7 @@ describe Puppet::Type.type(:file).attrclass(:source) do it "should fail if no specified sources can be found" do @source = source.new(:resource => @resource, :value => "/foo/bar") - Puppet::FileServing::Metadata.expects(:find).with("/foo/bar").returns nil + Puppet::FileServing::Metadata.indirection.expects(:find).with("/foo/bar").returns nil @source.expects(:fail).raises RuntimeError @@ -96,7 +96,7 @@ describe Puppet::Type.type(:file).attrclass(:source) do expirer = stub 'expired', :dependent_data_expired? => true metadata = stub 'metadata', :source= => nil - Puppet::FileServing::Metadata.expects(:find).with("/fee/booz").returns metadata + Puppet::FileServing::Metadata.indirection.expects(:find).with("/fee/booz").returns metadata @source = source.new(:resource => @resource, :value => ["/fee/booz"]) @source.metadata = "foo" diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index 7d93dfd64..943a3c38a 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -510,47 +510,47 @@ describe Puppet::Type.type(:file) do describe "when executing a recursive search" do it "should use Metadata to do its recursion" do - Puppet::FileServing::Metadata.expects(:search) + Puppet::FileServing::Metadata.indirection.expects(:search) @file.perform_recursion(@file[:path]) end it "should use the provided path as the key to the search" do - Puppet::FileServing::Metadata.expects(:search).with { |key, options| key == "/foo" } + Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| key == "/foo" } @file.perform_recursion("/foo") end it "should return the results of the metadata search" do - Puppet::FileServing::Metadata.expects(:search).returns "foobar" + Puppet::FileServing::Metadata.indirection.expects(:search).returns "foobar" @file.perform_recursion(@file[:path]).should == "foobar" end it "should pass its recursion value to the search" do @file[:recurse] = true - Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:recurse] == true } + Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true } @file.perform_recursion(@file[:path]) end it "should pass true if recursion is remote" do @file[:recurse] = :remote - Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:recurse] == true } + Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurse] == true } @file.perform_recursion(@file[:path]) end it "should pass its recursion limit value to the search" do @file[:recurselimit] = 10 - Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:recurselimit] == 10 } + Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:recurselimit] == 10 } @file.perform_recursion(@file[:path]) end it "should configure the search to ignore or manage links" do @file[:links] = :manage - Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:links] == :manage } + Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:links] == :manage } @file.perform_recursion(@file[:path]) end it "should pass its 'ignore' setting to the search if it has one" do @file[:ignore] = %w{.svn CVS} - Puppet::FileServing::Metadata.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} } + Puppet::FileServing::Metadata.indirection.expects(:search).with { |key, options| options[:ignore] == %w{.svn CVS} } @file.perform_recursion(@file[:path]) end end @@ -597,7 +597,7 @@ describe Puppet::Type.type(:file) do it "should set checksum_type to none if this file checksum is none" do @file[:checksum] = :none - Puppet::FileServing::Metadata.expects(:search).with { |path,params| params[:checksum_type] == :none }.returns [@metadata] + Puppet::FileServing::Metadata.indirection.expects(:search).with { |path,params| params[:checksum_type] == :none }.returns [@metadata] @file.expects(:newchild).with("my/file").returns "fiebar" @file.recurse_local end diff --git a/spec/unit/type/host_spec.rb b/spec/unit/type/host_spec.rb new file mode 100755 index 000000000..12ae2af08 --- /dev/null +++ b/spec/unit/type/host_spec.rb @@ -0,0 +1,83 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +ssh_authorized_key = Puppet::Type.type(:ssh_authorized_key) + +describe Puppet::Type.type(:host) do + before do + @class = Puppet::Type.type(:host) + @catalog = Puppet::Resource::Catalog.new + end + + it "should have :name be its namevar" do + @class.key_attributes.should == [:name] + end + + describe "when validating attributes" do + [:name, :provider ].each do |param| + it "should have a #{param} parameter" do + @class.attrtype(param).should == :param + end + end + + [:ip, :target, :host_aliases, :comment, :ensure].each do |property| + it "should have a #{property} property" do + @class.attrtype(property).should == :property + end + end + end + + describe "when validating values" do + it "should support present as a value for ensure" do + proc { @class.new(:name => "foo", :ensure => :present) }.should_not raise_error + end + + it "should support absent as a value for ensure" do + proc { @class.new(:name => "foo", :ensure => :absent) }.should_not raise_error + end + + it "should accept IPv4 addresses" do + proc { @class.new(:name => "foo", :ip => '10.96.0.1') }.should_not raise_error + end + + it "should accept long IPv6 addresses" do + # Taken from wikipedia article about ipv6 + proc { @class.new(:name => "foo", :ip => '2001:0db8:85a3:08d3:1319:8a2e:0370:7344') }.should_not raise_error + end + + it "should accept one host_alias" do + proc { @class.new(:name => "foo", :host_aliases => 'alias1') }.should_not raise_error + end + + it "should accept multiple host_aliases" do + proc { @class.new(:name => "foo", :host_aliases => [ 'alias1', 'alias2' ]) }.should_not raise_error + end + + it "should accept shortened IPv6 addresses" do + proc { @class.new(:name => "foo", :ip => '2001:db8:0:8d3:0:8a2e:70:7344') }.should_not raise_error + proc { @class.new(:name => "foo", :ip => '::ffff:192.0.2.128') }.should_not raise_error + proc { @class.new(:name => "foo", :ip => '::1') }.should_not raise_error + end + + it "should not accept malformed IPv4 addresses like 192.168.0.300" do + proc { @class.new(:name => "foo", :ip => '192.168.0.300') }.should raise_error + end + + it "should not accept malformed IP addresses like 2001:0dg8:85a3:08d3:1319:8a2e:0370:7344" do + proc { @class.new(:name => "foo", :ip => '2001:0dg8:85a3:08d3:1319:8a2e:0370:7344') }.should raise_error + end + + it "should not accept spaces in resourcename" do + proc { @class.new(:name => "foo bar") }.should raise_error + end + + it "should not accept host_aliases with spaces" do + proc { @class.new(:name => "foo", :host_aliases => [ 'well_formed', 'not wellformed' ]) }.should raise_error + end + + it "should not accept empty host_aliases" do + proc { @class.new(:name => "foo", :host_aliases => ['alias1','']) }.should raise_error + end + end +end diff --git a/spec/unit/type/mount_spec.rb b/spec/unit/type/mount_spec.rb index ce82cb516..4aa9baf70 100755 --- a/spec/unit/type/mount_spec.rb +++ b/spec/unit/type/mount_spec.rb @@ -203,23 +203,45 @@ describe Puppet::Type.type(:mount)::Ensure do end end - describe Puppet::Type.type(:mount), "when responding to events" do + describe Puppet::Type.type(:mount), "when responding to refresh" do - it "should remount if it is currently mounted" do - @provider.expects(:mounted?).returns(true) + it "should remount if it is supposed to be mounted" do + @mount[:ensure] = "mounted" @provider.expects(:remount) @mount.refresh end - it "should not remount if it is not currently mounted" do - @provider.expects(:mounted?).returns(false) + it "should not remount if it is supposed to be present" do + @mount[:ensure] = "present" + @provider.expects(:remount).never + + @mount.refresh + end + + it "should not remount if it is supposed to be absent" do + @mount[:ensure] = "absent" + @provider.expects(:remount).never + + @mount.refresh + end + + it "should not remount if it is supposed to be defined" do + @mount[:ensure] = "defined" + @provider.expects(:remount).never + + @mount.refresh + end + + it "should not remount if it is supposed to be unmounted" do + @mount[:ensure] = "unmounted" @provider.expects(:remount).never @mount.refresh end it "should not remount swap filesystems" do + @mount[:ensure] = "mounted" @mount[:fstype] = "swap" @provider.expects(:remount).never diff --git a/spec/unit/type/service_spec.rb b/spec/unit/type/service_spec.rb index 0958a69fa..77628670a 100755 --- a/spec/unit/type/service_spec.rb +++ b/spec/unit/type/service_spec.rb @@ -66,6 +66,10 @@ describe Puppet::Type.type(:service), "when validating attribute values" do Puppet::Type.type(:service).new(:name => "yay", :hasstatus => :false) end + it "should specify :true as the default value of hasstatus" do + Puppet::Type.type(:service).new(:name => "yay")[:hasstatus].should == :true + end + it "should support :true as a value to :hasrestart" do Puppet::Type.type(:service).new(:name => "yay", :hasrestart => :true) end diff --git a/spec/unit/type/sshkey_spec.rb b/spec/unit/type/sshkey_spec.rb new file mode 100644 index 000000000..966ca7099 --- /dev/null +++ b/spec/unit/type/sshkey_spec.rb @@ -0,0 +1,71 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +sshkey = Puppet::Type.type(:sshkey) + +describe sshkey do + before do + @class = sshkey + end + + it "should have :name its namevar" do + @class.key_attributes.should == [:name] + end + + describe "when validating attributes" do + [:name, :provider].each do |param| + it "should have a #{param} parameter" do + @class.attrtype(param).should == :param + end + end + + [:host_aliases, :ensure, :key, :type].each do |property| + it "should have a #{property} property" do + @class.attrtype(property).should == :property + end + end + end + + describe "when validating values" do + + it "should support ssh-dss as a type value" do + proc { @class.new(:name => "foo", :type => "ssh-dss") }.should_not raise_error + end + + it "should support ssh-rsa as a type value" do + proc { @class.new(:name => "whev", :type => "ssh-rsa") }.should_not raise_error + end + + it "should alias :dsa to ssh-dss as a value for type" do + key = @class.new(:name => "whev", :type => :dsa) + key.should(:type).should == :'ssh-dss' + end + + it "should alias :rsa to ssh-rsa as a value for type" do + key = @class.new(:name => "whev", :type => :rsa) + key.should(:type).should == :'ssh-rsa' + end + + it "should not support values other than ssh-dss, ssh-rsa, dsa, rsa for type" do + proc { @class.new(:name => "whev", :type => :'ssh-dsa') }.should raise_error(Puppet::Error) + end + + it "should accept one host_alias" do + proc { @class.new(:name => "foo", :host_aliases => 'foo.bar.tld') }.should_not raise_error + end + + it "should accept multiple host_aliases as an array" do + proc { @class.new(:name => "foo", :host_aliases => ['foo.bar.tld','10.0.9.9']) }.should_not raise_error + end + + it "should not accept spaces in any host_alias" do + proc { @class.new(:name => "foo", :host_aliases => ['foo.bar.tld','foo bar']) }.should raise_error(Puppet::Error) + end + + it "should not accept aliases in the resourcename" do + proc { @class.new(:name => 'host,host.domain,ip') }.should raise_error(Puppet::Error) + end + + end +end diff --git a/spec/unit/type/tidy_spec.rb b/spec/unit/type/tidy_spec.rb index 11edbfbf3..1573ead1b 100755 --- a/spec/unit/type/tidy_spec.rb +++ b/spec/unit/type/tidy_spec.rb @@ -110,7 +110,8 @@ describe tidy do :b => 0, :kb => 1, :mb => 2, - :gb => 3 + :gb => 3, + :tb => 4 } convertors.each do |unit, multiple| diff --git a/spec/unit/util/log_spec.rb b/spec/unit/util/log_spec.rb index 7d96fe190..ea5d59859 100755 --- a/spec/unit/util/log_spec.rb +++ b/spec/unit/util/log_spec.rb @@ -7,7 +7,7 @@ require 'puppet/util/log' describe Puppet::Util::Log do it "should write a given message to the specified destination" do arraydest = [] - Puppet::Util::Log.newdestination(arraydest) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(arraydest)) Puppet::Util::Log.new(:level => :notice, :message => "foo") message = arraydest.last.message message.should == "foo" @@ -87,7 +87,7 @@ describe Puppet::Util::Log do it "should flush the log queue when the first destination is specified" do Puppet::Util::Log.close_all Puppet::Util::Log.expects(:flushqueue) - Puppet::Util::Log.newdestination([]) + Puppet::Util::Log.newdestination(:console) end it "should convert the level to a symbol if it's passed in as a string" do diff --git a/spec/unit/util/monkey_patches_spec.rb b/spec/unit/util/monkey_patches_spec.rb index b0f61c808..049ed1044 100644 --- a/spec/unit/util/monkey_patches_spec.rb +++ b/spec/unit/util/monkey_patches_spec.rb @@ -5,3 +5,29 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f require 'puppet/util/monkey_patches' + +describe "yaml deserialization" do + it "should call yaml_initialize when deserializing objects that have that method defined" do + class Puppet::TestYamlInitializeClass + attr_reader :foo + + def yaml_initialize(tag, var) + var.should == {'foo' => 100} + instance_variables.should == [] + @foo = 200 + end + end + + obj = YAML.load("--- !ruby/object:Puppet::TestYamlInitializeClass\n foo: 100") + obj.foo.should == 200 + end + + it "should not call yaml_initialize if not defined" do + class Puppet::TestYamlNonInitializeClass + attr_reader :foo + end + + obj = YAML.load("--- !ruby/object:Puppet::TestYamlNonInitializeClass\n foo: 100") + obj.foo.should == 100 + end +end diff --git a/spec/unit/util/pson_spec.rb b/spec/unit/util/pson_spec.rb index d02d28517..474ddafa4 100755 --- a/spec/unit/util/pson_spec.rb +++ b/spec/unit/util/pson_spec.rb @@ -35,4 +35,19 @@ describe Puppet::Util::Pson do bin_string = (1..20000).collect { |i| ((17*i+13*i*i) % 255).chr }.join PSON.parse(%Q{{ "type": "foo", "data": #{bin_string.to_pson} }})["data"].should == bin_string end + + it "should be able to handle UTF8 that isn't a real unicode character" do + s = ["\355\274\267"] + PSON.parse( [s].to_pson ).should == [s] + end + + it "should be able to handle UTF8 for \\xFF" do + s = ["\xc3\xbf"] + PSON.parse( [s].to_pson ).should == [s] + end + + it "should be able to handle invalid UTF8 bytes" do + s = ["\xc3\xc3"] + PSON.parse( [s].to_pson ).should == [s] + end end diff --git a/spec/unit/util/rdoc/parser_spec.rb b/spec/unit/util/rdoc/parser_spec.rb index 28c33c295..04713f293 100755 --- a/spec/unit/util/rdoc/parser_spec.rb +++ b/spec/unit/util/rdoc/parser_spec.rb @@ -20,7 +20,7 @@ describe RDoc::Parser do @parser.stubs(:scan_top_level) parser = stub 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) - parser.expects(:parse) + parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) parser.expects(:file=).with("module/manifests/init.pp") @parser.scan @@ -29,6 +29,7 @@ describe RDoc::Parser do it "should scan the ast for Puppet files" do parser = stub_everything 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) + parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @parser.expects(:scan_top_level) @@ -38,6 +39,7 @@ describe RDoc::Parser do it "should return a PuppetTopLevel to RDoc" do parser = stub_everything 'parser' Puppet::Parser::Parser.stubs(:new).returns(parser) + parser.expects(:parse).returns(Puppet::Parser::AST::Hostclass.new('')) @parser.expects(:scan_top_level) @@ -47,8 +49,8 @@ describe RDoc::Parser do describe "when scanning top level entities" do before :each do - @resource_type_collection = stub_everything 'resource_type_collection' - @parser.ast = @resource_type_collection + @resource_type_collection = resource_type_collection = stub_everything('resource_type_collection') + @parser.instance_eval { @known_resource_types = resource_type_collection } @parser.stubs(:split_module).returns("module") @topcontainer = stub_everything 'topcontainer' @@ -141,8 +143,8 @@ describe RDoc::Parser do @definition = stub_everything 'definition', :file => "module/manifests/init.pp", :type => :definition, :name => "mydef" @node = stub_everything 'node', :file => "module/manifests/init.pp", :type => :node, :name => "mynode" - @resource_type_collection = Puppet::Resource::TypeCollection.new("env") - @parser.ast = @resource_type_collection + @resource_type_collection = resource_type_collection = Puppet::Resource::TypeCollection.new("env") + @parser.instance_eval { @known_resource_types = resource_type_collection } @container = stub_everything 'container' end @@ -437,9 +439,13 @@ describe RDoc::Parser do @class = stub_everything 'class' @stmt = Puppet::Parser::AST::Resource.new( :type => "File", - :title => "myfile", - :doc => 'mydoc', - :parameters => Puppet::Parser::AST::ASTArray.new(:children => []) + :instances => Puppet::Parser::AST::ASTArray.new(:children => [ + Puppet::Parser::AST::ResourceInstance.new( + :title => Puppet::Parser::AST::Name.new(:value => "myfile"), + :parameters => Puppet::Parser::AST::ASTArray.new(:children => []) + ) + ]), + :doc => 'mydoc' ) @code = stub_everything 'code' diff --git a/spec/unit/util/zaml_spec.rb b/spec/unit/util/zaml_spec.rb index f2bcefe01..358c6aa11 100755 --- a/spec/unit/util/zaml_spec.rb +++ b/spec/unit/util/zaml_spec.rb @@ -35,5 +35,29 @@ describe "Pure ruby yaml implementation" do lambda { YAML.load(o.to_yaml) }.should_not raise_error end } -end + it "should emit proper labels and backreferences for common objects" do + # Note: this test makes assumptions about the names ZAML chooses + # for labels. + x = [1, 2] + y = [3, 4] + z = [x, y, x, y] + z.to_yaml.should == "--- \n - &id001\n - 1\n - 2\n - &id002\n - 3\n - 4\n - *id001\n - *id002" + z2 = YAML.load(z.to_yaml) + z2.should == z + z2[0].should equal(z2[2]) + z2[1].should equal(z2[3]) + end + + it "should emit proper labels and backreferences for recursive objects" do + x = [1, 2] + x << x + x.to_yaml.should == "--- &id001\n \n - 1\n - 2\n - *id001" + x2 = YAML.load(x.to_yaml) + x2.should be_a(Array) + x2.length.should == 3 + x2[0].should == 1 + x2[1].should == 2 + x2[2].should equal(x2) + end +end diff --git a/tasks/rake/git_workflow.rake b/tasks/rake/git_workflow.rake index b2f96c603..4c39f98de 100644 --- a/tasks/rake/git_workflow.rake +++ b/tasks/rake/git_workflow.rake @@ -103,10 +103,21 @@ task :mail_patches do # Create all of the patches sh "git format-patch -C -M -s -n --subject-prefix='PATCH/puppet' #{parent}..HEAD" + # Add info to the patches + additional_info = "Local-branch: #{branch}\n" + files = Dir.glob("00*.patch") + files.each do |file| + contents = File.read(file) + contents.sub!(/^---\n/, "---\n#{additional_info}") + File.open(file, 'w') do |file_handle| + file_handle.print contents + end + end + # And then mail them out. # If we've got more than one patch, add --compose - if Dir.glob("00*.patch").length > 1 + if files.length > 1 compose = "--compose" else compose = "" diff --git a/test/data/providers/host/parsed/valid_hosts b/test/data/providers/host/parsed/valid_hosts new file mode 100644 index 000000000..24636295d --- /dev/null +++ b/test/data/providers/host/parsed/valid_hosts @@ -0,0 +1,19 @@ +# Some leading comment, that should be ignored +# The next line is empty so it should be ignored + +::1 localhost + +# We now try another delimiter: Several tabs +127.0.0.1 localhost + +# No test trailing spaces +10.0.0.1 host1 + +# Ok its time to test aliases +2001:252:0:1::2008:8 ipv6host alias1 +192.168.0.1 ipv4host alias2 alias3 + +# Testing inlinecomments now +192.168.0.2 host3 # This is host3 +192.168.0.3 host4 alias10 # This is host4 +192.168.0.4 host5 alias11 alias12 # This is host5 diff --git a/test/language/functions.rb b/test/language/functions.rb index 1d4ed8241..081063e2b 100755 --- a/test/language/functions.rb +++ b/test/language/functions.rb @@ -451,7 +451,7 @@ class TestLangFunctions < Test::Unit::TestCase scope.function_include("nosuchclass") end - parser.newclass("myclass") + scope.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "myclass", {}) scope.compiler.expects(:evaluate_classes).with(%w{myclass otherclass}, scope, false).returns(%w{myclass otherclass}) diff --git a/test/language/parser.rb b/test/language/parser.rb index 8cda8eeb2..93d4ae693 100755 --- a/test/language/parser.rb +++ b/test/language/parser.rb @@ -39,9 +39,8 @@ class TestParser < Test::Unit::TestCase failers { |file| parser = mkparser Puppet.debug("parsing failer #{file}") if __FILE__ == $0 - assert_raise(Puppet::ParseError, "Did not fail while parsing #{file}") { - parser.file = file - ast = parser.parse + assert_raise(Puppet::ParseError, Puppet::Error, "Did not fail while parsing #{file}") { + Puppet[:manifest] = file config = mkcompiler(parser) config.compile #ast.hostclass("").evaluate config.topscope @@ -288,7 +287,7 @@ class TestParser < Test::Unit::TestCase ret = parser.parse } - ret.hostclass("").code.each do |obj| + ret.code.each do |obj| assert_instance_of(AST::Collection, obj) end end @@ -362,12 +361,12 @@ file { "/tmp/yayness": assert_raise(Puppet::ParseError) { - parser.parse %{define mydef($schedule) {}} + parser.known_resource_types.import_ast(parser.parse(%{define mydef($schedule) {}}), '') } assert_nothing_raised { - parser.parse %{define adef($schedule = false) {}} - parser.parse %{define mydef($schedule = daily) {}} + parser.known_resource_types.import_ast(parser.parse(%{define adef($schedule = false) {}}), '') + parser.known_resource_types.import_ast(parser.parse(%{define mydef($schedule = daily) {}}), '') } end @@ -379,12 +378,12 @@ file { "/tmp/yayness": str1 = %{if true { #{exec.call("true")} }} ret = nil assert_nothing_raised { - ret = parser.parse(str1).hostclass("").code[0] + ret = parser.parse(str1).code[0] } assert_instance_of(Puppet::Parser::AST::IfStatement, ret) parser = mkparser str2 = %{if true { #{exec.call("true")} } else { #{exec.call("false")} }} - ret = parser.parse(str2).hostclass("").code[0] + ret = parser.parse(str2).code[0] assert_instance_of(Puppet::Parser::AST::IfStatement, ret) assert_instance_of(Puppet::Parser::AST::Else, ret.else) end @@ -393,23 +392,23 @@ file { "/tmp/yayness": parser = mkparser assert_nothing_raised { - parser.parse %{class myclass { class other {} }} + parser.known_resource_types.import_ast(parser.parse(%{class myclass { class other {} }}), '') } assert(parser.hostclass("myclass"), "Could not find myclass") assert(parser.hostclass("myclass::other"), "Could not find myclass::other") assert_nothing_raised { - parser.parse "class base {} + parser.known_resource_types.import_ast(parser.parse("class base {} class container { class deep::sub inherits base {} - }" + }"), '') } sub = parser.hostclass("container::deep::sub") assert(sub, "Could not find sub") # Now try it with a parent class being a fq class assert_nothing_raised { - parser.parse "class container::one inherits container::deep::sub {}" + parser.known_resource_types.import_ast(parser.parse("class container::one inherits container::deep::sub {}"), '') } sub = parser.hostclass("container::one") assert(sub, "Could not find one") @@ -417,7 +416,7 @@ file { "/tmp/yayness": # Finally, try including a qualified class assert_nothing_raised("Could not include fully qualified class") { - parser.parse "include container::deep::sub" + parser.known_resource_types.import_ast(parser.parse("include container::deep::sub"), '') } end @@ -426,20 +425,11 @@ file { "/tmp/yayness": # Make sure we put the top-level code into a class called "" in # the "" namespace - assert_nothing_raised do - out = parser.parse "" - - assert_instance_of(Puppet::Resource::TypeCollection, out) - assert_nil(parser.hostclass(""), "Got a 'main' class when we had no code") - end - - # Now try something a touch more complicated parser.initvars assert_nothing_raised do - out = parser.parse "Exec { path => '/usr/bin:/usr/sbin' }" - assert_instance_of(Puppet::Resource::TypeCollection, out) - assert_equal("", parser.hostclass("").name) - assert_equal("", parser.hostclass("").namespace) + parser.known_resource_types.import_ast(parser.parse("Exec { path => '/usr/bin:/usr/sbin' }"), '') + assert_equal("", parser.known_resource_types.hostclass("").name) + assert_equal("", parser.known_resource_types.hostclass("").namespace) end end @@ -482,22 +472,26 @@ file { "/tmp/yayness": ret = nil assert_nothing_raised do - ret = parser.parse("#{at}file { '/tmp/testing': owner => root }") + parser.known_resource_types.import_ast(parser.parse("#{at}file { '/tmp/testing': owner => root }"), '') + ret = parser.known_resource_types end assert_instance_of(AST::ASTArray, ret.hostclass("").code) resdef = ret.hostclass("").code[0] assert_instance_of(AST::Resource, resdef) - assert_equal("/tmp/testing", resdef.title.value) + assert_instance_of(AST::ASTArray, resdef.instances) + assert_equal(1, resdef.instances.children.length) + assert_equal("/tmp/testing", resdef.instances[0].title.value) # We always get an astarray back, so... check.call(resdef, "simple resource") # Now let's try it with multiple resources in the same spec assert_nothing_raised do - ret = parser.parse("#{at}file { ['/tmp/1', '/tmp/2']: owner => root }") + parser.known_resource_types.import_ast(parser.parse("#{at}file { ['/tmp/1', '/tmp/2']: owner => root }"), '') + ret = parser.known_resource_types end - ret.hostclass("").code.each do |res| + ret.hostclass("").code[0].each do |res| assert_instance_of(AST::Resource, res) check.call(res, "multiresource") end @@ -506,9 +500,9 @@ file { "/tmp/yayness": ensure if Puppet.features.rails? Puppet[:storeconfigs] = false - Puppet::Resource::Catalog.cache_class = catalog_cache_class - Puppet::Node::Facts.cache_class = facts_cache_class - Puppet::Node.cache_class = node_cache_class + Puppet::Resource::Catalog.indirection.cache_class = catalog_cache_class + Puppet::Node::Facts.indirection.cache_class = facts_cache_class + Puppet::Node.indirection.cache_class = node_cache_class end end @@ -537,7 +531,7 @@ file { "/tmp/yayness": ret = parser.parse("File #{arrow}") end - coll = ret.hostclass("").code[0] + coll = ret.code[0] assert_instance_of(AST::Collection, coll) assert_equal(form, coll.form) end @@ -545,9 +539,9 @@ file { "/tmp/yayness": ensure if Puppet.features.rails? Puppet[:storeconfigs] = false - Puppet::Resource::Catalog.cache_class = catalog_cache_class - Puppet::Node::Facts.cache_class = facts_cache_class - Puppet::Node.cache_class = node_cache_class + Puppet::Resource::Catalog.indirection.cache_class = catalog_cache_class + Puppet::Node::Facts.indirection.cache_class = facts_cache_class + Puppet::Node.indirection.cache_class = node_cache_class end end @@ -560,7 +554,7 @@ file { "/tmp/yayness": res = nil assert_nothing_raised do - res = parser.parse(str).hostclass("").code[0] + res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) @@ -583,7 +577,7 @@ file { "/tmp/yayness": res = nil assert_nothing_raised do - res = parser.parse(str).hostclass("").code[0] + res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) @@ -607,7 +601,7 @@ file { "/tmp/yayness": res = nil assert_nothing_raised("Could not parse '#{test}'") do - res = parser.parse(str).hostclass("").code[0] + res = parser.parse(str).code[0] end assert_instance_of(AST::Collection, res) @@ -624,15 +618,11 @@ file { "/tmp/yayness": def test_fully_qualified_definitions parser = mkparser + types = parser.known_resource_types assert_nothing_raised("Could not parse fully-qualified definition") { - parser.parse %{define one::two { }} + types.import_ast(parser.parse(%{define one::two { }}), '') } assert(parser.definition("one::two"), "Could not find one::two with no namespace") - - # Now try using the definition - assert_nothing_raised("Could not parse fully-qualified definition usage") { - parser.parse %{one::two { yayness: }} - } end # #524 @@ -691,7 +681,7 @@ file { "/tmp/yayness": result = parser.parse %{$variable = undef} } - main = result.hostclass("").code + main = result.code children = main.children assert_instance_of(AST::VarDef, main.children[0]) assert_instance_of(AST::Undef, main.children[0].value) @@ -704,7 +694,8 @@ file { "/tmp/yayness": str = "file { '/tmp/yay': ensure => file }\nclass yay {}\nnode foo {}\ndefine bar {}\n" result = nil assert_nothing_raised("Could not parse") do - result = parser.parse(str) + parser.known_resource_types.import_ast(parser.parse(str), '') + result = parser.known_resource_types end assert_instance_of(Puppet::Resource::TypeCollection, result, "Did not get a ASTSet back from parsing") @@ -734,12 +725,14 @@ file { "/tmp/yayness": result = nil assert_nothing_raised do - result = parser.newclass "Yayness" + parser.known_resource_types.import_ast(parser.parse("class yayness { }"), '') + result = parser.known_resource_types.hostclass('yayness') end assert_equal(result, parser.find_hostclass("", "yayNess")) assert_nothing_raised do - result = parser.newdefine "FunTest" + parser.known_resource_types.import_ast(parser.parse("define funtest { }"), '') + result = parser.known_resource_types.definition('funtest') end assert_equal(result, parser.find_definition("", "fUntEst"), "#{"fUntEst"} was not matched") end diff --git a/test/language/scope.rb b/test/language/scope.rb index cb5558aec..15c321166 100755 --- a/test/language/scope.rb +++ b/test/language/scope.rb @@ -163,7 +163,7 @@ class TestScope < Test::Unit::TestCase config = mkcompiler # Create a default source - parser.newclass("") + parser.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "") config.topscope.source = parser.known_resource_types.hostclass("") # And a scope resource @@ -175,12 +175,12 @@ class TestScope < Test::Unit::TestCase ) # Create a top-level define - parser.newdefine "one", :arguments => [%w{arg}], + parser.known_resource_types.add Puppet::Resource::Type.new(:definition, "one", :arguments => [%w{arg}], :code => AST::ASTArray.new( :children => [ resourcedef("file", "/tmp", {"owner" => varref("arg")}) ] - ) + )) # create a resource that calls our third define obj = resourcedef("one", "boo", {"arg" => "parentfoo"}) @@ -233,9 +233,9 @@ Host <<||>>" } ensure Puppet[:storeconfigs] = false - Puppet::Resource::Catalog.cache_class = catalog_cache_class - Puppet::Node::Facts.cache_class = facts_cache_class - Puppet::Node.cache_class = node_cache_class + Puppet::Resource::Catalog.indirection.cache_class = catalog_cache_class + Puppet::Node::Facts.indirection.cache_class = facts_cache_class + Puppet::Node.indirection.cache_class = node_cache_class end else $stderr.puts "No ActiveRecord -- skipping collection tests" diff --git a/test/language/snippets.rb b/test/language/snippets.rb index 51c5e23fe..e5b513a46 100755 --- a/test/language/snippets.rb +++ b/test/language/snippets.rb @@ -501,7 +501,7 @@ class TestSnippets < Test::Unit::TestCase catalog = nil assert_nothing_raised("Could not compile catalog") { - catalog = Puppet::Resource::Catalog.find(node) + catalog = Puppet::Resource::Catalog.indirection.find(node) } assert_nothing_raised("Could not convert catalog") { diff --git a/test/lib/puppettest.rb b/test/lib/puppettest.rb index 0b3a89a72..a60092cf7 100755 --- a/test/lib/puppettest.rb +++ b/test/lib/puppettest.rb @@ -185,7 +185,7 @@ module PuppetTest #if rake? or ! Puppet[:debug] #if defined?($puppet_debug) or ! rake? Puppet[:color] = false if textmate? - Puppet::Util::Log.newdestination(@logs) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) if defined? $console Puppet.info @method_name Puppet::Util::Log.newdestination(:console) @@ -305,7 +305,7 @@ module PuppetTest def logstore @logs = [] - Puppet::Util::Log.newdestination(@logs) + Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs)) end end diff --git a/test/lib/puppettest/parsertesting.rb b/test/lib/puppettest/parsertesting.rb index bd04c1ec5..411bad37a 100644 --- a/test/lib/puppettest/parsertesting.rb +++ b/test/lib/puppettest/parsertesting.rb @@ -94,16 +94,15 @@ module PuppetTest::ParserTesting def resourcedef(type, title, params) title = stringobj(title) unless title.is_a?(AST) + instance = AST::ResourceInstance.new(:title => title, :parameters => resourceparams(params)) assert_nothing_raised("Could not create #{type} #{title}") { return AST::Resource.new( :file => __FILE__, :line => __LINE__, - :title => title, :type => type, - - :parameters => resourceinst(params) + :instances => AST::ASTArray.new(:children => [instance]) ) } end @@ -122,9 +121,7 @@ module PuppetTest::ParserTesting :file => __FILE__, :line => __LINE__, :object => resourceref(type, title), - - :type => type, - :parameters => resourceinst(params) + :parameters => resourceparams(params) ) } end @@ -197,13 +194,13 @@ module PuppetTest::ParserTesting } end - def resourceinst(hash) + def resourceparams(hash) assert_nothing_raised("Could not create resource instance") { params = hash.collect { |param, value| resourceparam(param, value) } - return AST::ResourceInstance.new( + return AST::ASTArray.new( :file => tempfile, diff --git a/test/network/handler/master.rb b/test/network/handler/master.rb index 81869ac06..f4bad7037 100755 --- a/test/network/handler/master.rb +++ b/test/network/handler/master.rb @@ -13,7 +13,7 @@ class TestMaster < Test::Unit::TestCase @master = Puppet::Network::Handler.master.new(:Manifest => tempfile) @catalog = stub 'catalog', :extract => "" - Puppet::Resource::Catalog.stubs(:find).returns(@catalog) + Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog) end def teardown @@ -32,15 +32,17 @@ class TestMaster < Test::Unit::TestCase def test_hostname_is_used_if_client_is_missing @master.expects(:decode_facts).returns("hostname" => "yay") - Puppet::Node::Facts.expects(:new).with { |name, facts| name == "yay" }.returns(stub('facts', :save => nil)) + facts = Puppet::Node::Facts.new("the_facts") + Puppet::Node::Facts.indirection.stubs(:save).with(facts) + Puppet::Node::Facts.expects(:new).with { |name, facts| name == "yay" }.returns(facts) @master.getconfig("facts") end def test_facts_are_saved - facts = mock('facts') + facts = Puppet::Node::Facts.new("the_facts") Puppet::Node::Facts.expects(:new).returns(facts) - facts.expects(:save) + Puppet::Node::Facts.indirection.expects(:save).with(facts) @master.stubs(:decode_facts) @@ -48,12 +50,13 @@ class TestMaster < Test::Unit::TestCase end def test_catalog_is_used_for_compiling - facts = stub('facts', :save => nil) + facts = Puppet::Node::Facts.new("the_facts") + Puppet::Node::Facts.indirection.stubs(:save).with(facts) Puppet::Node::Facts.stubs(:new).returns(facts) @master.stubs(:decode_facts) - Puppet::Resource::Catalog.expects(:find).with("foo.com").returns(@catalog) + Puppet::Resource::Catalog.indirection.expects(:find).with("foo.com").returns(@catalog) @master.getconfig("facts", "yaml", "foo.com") end @@ -61,14 +64,15 @@ end class TestMasterFormats < Test::Unit::TestCase def setup - @facts = stub('facts', :save => nil) + @facts = Puppet::Node::Facts.new("the_facts") Puppet::Node::Facts.stubs(:new).returns(@facts) + Puppet::Node::Facts.indirection.stubs(:save) @master = Puppet::Network::Handler.master.new(:Code => "") @master.stubs(:decode_facts) @catalog = stub 'catalog', :extract => "" - Puppet::Resource::Catalog.stubs(:find).returns(@catalog) + Puppet::Resource::Catalog.indirection.stubs(:find).returns(@catalog) end def test_marshal_can_be_used diff --git a/test/rails/railsparameter.rb b/test/rails/railsparameter.rb index 9f6fc1c1e..77ce33912 100755 --- a/test/rails/railsparameter.rb +++ b/test/rails/railsparameter.rb @@ -22,7 +22,7 @@ class TestRailsParameter < Test::Unit::TestCase # Now create a source parser = mkparser - source = parser.newclass "myclass" + source = parser.known_resource_types.add Puppet::Resource::Type.new(:hostclass, "myclass") host = Puppet::Rails::Host.new(:name => "myhost") diff --git a/test/ral/providers/cron/crontab.rb b/test/ral/providers/cron/crontab.rb index 0c87a5bba..be2af1e16 100755 --- a/test/ral/providers/cron/crontab.rb +++ b/test/ral/providers/cron/crontab.rb @@ -97,7 +97,10 @@ class TestCronParsedProvider < Test::Unit::TestCase # Then do them all at once. records = [] text = "" - sample_records.each do |name, options| + # Sort sample_records so that the :empty entry does not come last + # (if it does, the test will fail because the empty last line will + # be ignored) + sample_records.sort { |a, b| a.first.to_s <=> b.first.to_s }.each do |name, options| records << options[:record] text += options[:text] + "\n" end diff --git a/test/ral/providers/host/parsed.rb b/test/ral/providers/host/parsed.rb index c2367d566..955edd5d3 100755 --- a/test/ral/providers/host/parsed.rb +++ b/test/ral/providers/host/parsed.rb @@ -67,7 +67,8 @@ class TestParsedHostProvider < Test::Unit::TestCase # Make sure we convert both directlys correctly using a simple host. def test_basic_isomorphism - hash = {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}} + hash = {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}, + :comment => ''} str = nil assert_nothing_raised do @@ -105,11 +106,13 @@ class TestParsedHostProvider < Test::Unit::TestCase [ {:record_type => :comment, :line => "# comment one"}, {:record_type => :blank, :line => ""}, - {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}}, + {:record_type => :parsed, :name => "myhost", :ip => "192.168.43.56", :host_aliases => %w{another host}, + :comment => ''}, {:record_type => :blank, :line => " "}, {:record_type => :comment, :line => "# another comment"}, - {:record_type => :parsed, :name => "anotherhost", :ip => "192.168.43.57", :host_aliases => []} + {:record_type => :parsed, :name => "anotherhost", :ip => "192.168.43.57", :host_aliases => [], + :comment => ''} ], instances) newtext = nil |