diff options
32 files changed, 1308 insertions, 402 deletions
@@ -13,8 +13,39 @@ Fixed #1840 - Bug fixes and improvements for Emacs puppet-mode.el +0.24.8 + Fixing #1543 - Nagios parse errors no longer kill Puppet + + Fixed #1420 - nagios_serviceescalation not allowing host_name more than one type + + Fixed #1884 - Exported resources are marked as unexported when collected on the exporting host + + Fixed #1922 - Functions squash all arguments into a single hash + + Fixed #1538 - Yumrepo sets permissions wrongly on files in /etc/yum.repos.d + + Fixed #1936 - Added /* */ support to the vim file + + Fixed #1541 - nagios objects write files to clientbucket on every change + + Fixed #1542 - cannot purge nagios objects + + Fixing #1912 - gid still works with no 'should' value fixing ralsh issues + + Fixing the Rakefile to use 'git format-patch' + + Added README.rst file + + Enhancements to Stored Configuration performance + + Added Reductive Labs build library to tasks directory + + Fixed #1852 - Correct behaviour when no SELinux bindings + Updated Red Hat spec file 0.24.7 + Fixed #1920 - Shadow password corruption + 0.24.7 Fixed #1804 - Added VDev and MultiVDev properties to the ZPool type @@ -1,5 +1,7 @@ # Rakefile for Puppet -*- ruby -*- +$LOAD_PATH << File.join(File.dirname(__FILE__), 'tasks') + $: << File.expand_path(File.join(File.dirname(__FILE__), 'lib')) begin @@ -191,7 +193,7 @@ task :mail_patches do type, parent, name = $1, $2, $3 # Create all of the patches - sh "git-format-patch -C -M -s -n #{parent}..HEAD" + sh "git format-patch -C -M -s -n #{parent}..HEAD" # And then mail them out. diff --git a/ext/vim/syntax/puppet.vim b/ext/vim/syntax/puppet.vim index a29e368e1..5a50f5ce0 100644 --- a/ext/vim/syntax/puppet.vim +++ b/ext/vim/syntax/puppet.vim @@ -49,6 +49,7 @@ syn keyword puppetControl case default " comments last overriding everything else syn match puppetComment "\s*#.*$" contains=puppetTodo +syn region puppetComment start="/\*" end="\*/" contains=puppetTodo extend syn keyword puppetTodo TODO NOTE FIXME XXX contained " Define the default highlighting. diff --git a/lib/puppet.rb b/lib/puppet.rb index c2d108d7f..2cbf7fb29 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -24,7 +24,7 @@ require 'puppet/util/suidmanager' # it's also a place to find top-level commands like 'debug' module Puppet - PUPPETVERSION = '0.24.6' + PUPPETVERSION = '0.24.7' def Puppet.version return PUPPETVERSION diff --git a/lib/puppet/external/nagios/base.rb b/lib/puppet/external/nagios/base.rb index 6a0c1831c..d95b808dd 100755 --- a/lib/puppet/external/nagios/base.rb +++ b/lib/puppet/external/nagios/base.rb @@ -416,20 +416,18 @@ class Nagios::Base :dependent_service_description, :host_name, :hostgroup_name, :service_description, :inherits_parent, :execution_failure_criteria, :notification_failure_criteria, :dependency_period, - :register, :use, - :_naginator_name + :register, :use - setnamevar :_naginator_name + setnamevar :service_description end newtype :serviceescalation do setparameters :host_name, :hostgroup_name, :service_description, :contacts, :contact_groups, :first_notification, :last_notification, :notification_interval, :escalation_period, :escalation_options, - :register, :use, - :_naginator_name + :register, :use - setnamevar :_naginator_name + setnamevar :service_description end newtype :hostdependency do @@ -437,20 +435,18 @@ class Nagios::Base setparameters :dependent_host_name, :dependent_hostgroup_name, :host_name, :hostgroup_name, :inherits_parent, :execution_failure_criteria, :notification_failure_criteria, :dependency_period, - :register, :use, - :_naginator_name + :register, :use - setnamevar :_naginator_name + setnamevar :host_name end newtype :hostescalation do setparameters :host_name, :hostgroup_name, :contacts, :contact_groups, :first_notification, :last_notification, :notification_interval, :escalation_period, :escalation_options, - :register, :use, - :_naginator_name + :register, :use - setnamevar :_naginator_name + setnamevar :host_name end newtype :hostextinfo do @@ -467,10 +463,9 @@ class Nagios::Base setparameters :host_name, :service_description, :notes, :notes_url, :action_url, :icon_image, :icon_image_alt, - :register, :use, - :_naginator_name + :register, :use - setnamevar :_naginator_name + setnamevar :service_description end end diff --git a/lib/puppet/external/nagios/grammar.ry b/lib/puppet/external/nagios/grammar.ry index f50818f1a..87c909280 100644 --- a/lib/puppet/external/nagios/grammar.ry +++ b/lib/puppet/external/nagios/grammar.ry @@ -55,6 +55,8 @@ end ----inner +class ::Nagios::Parser::SyntaxError < RuntimeError; end + def parse(src) @src = src @@ -66,12 +68,7 @@ def parse(src) @line = 0 @yydebug = true - begin - do_parse - rescue SyntaxError - $stderr.print "#{$!}\n" - exit - end + do_parse end # The lexer. Very simple. @@ -183,6 +180,6 @@ def on_error(token, value, vstack ) if token == '$end'.intern puts "okay, this is silly" else - raise SyntaxError, msg + raise ::Nagios::Parser::SyntaxError, msg end end diff --git a/lib/puppet/external/nagios/parser.rb b/lib/puppet/external/nagios/parser.rb index b7e2c21d8..d8a8bceea 100644 --- a/lib/puppet/external/nagios/parser.rb +++ b/lib/puppet/external/nagios/parser.rb @@ -1,22 +1,20 @@ # # DO NOT MODIFY!!!! -# This file is automatically generated by racc 1.4.4 +# This file is automatically generated by racc 1.4.5 # from racc grammer file "grammar.ry". # # # parser.rb: generated by racc (runtime embedded) # - -###### racc/parser.rb - +###### racc/parser.rb begin unless $".index 'racc/parser.rb' $".push 'racc/parser.rb' -self.class.module_eval <<'..end /usr/lib/ruby/1.8/racc/parser.rb modeval..id1306b79176', '/usr/lib/ruby/1.8/racc/parser.rb', 1 +self.class.module_eval <<'..end racc/parser.rb modeval..id5256434e8a', 'racc/parser.rb', 1 # -# parser.rb +# $Id: parser.rb,v 1.7 2005/11/20 17:31:32 aamine Exp $ # -# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net> +# Copyright (c) 1999-2005 Minero Aoki # # This program is free software. # You can distribute/modify this program under the same terms of ruby. @@ -25,8 +23,6 @@ self.class.module_eval <<'..end /usr/lib/ruby/1.8/racc/parser.rb modeval..id1306 # into a Racc output file, you may use that output file # without restriction. # -# $raccId: parser.rb,v 1.4 2003/11/03 13:41:47 aamine Exp $ -# unless defined?(NotImplementedError) NotImplementedError = NotImplementError @@ -39,7 +35,6 @@ unless defined?(::ParseError) ParseError = Racc::ParseError end - module Racc unless defined?(Racc_No_Extentions) @@ -48,14 +43,14 @@ module Racc class Parser - Racc_Runtime_Version = '1.4.4' - Racc_Runtime_Revision = '$raccRevision: 1.4 $'.split[1] + Racc_Runtime_Version = '1.4.5' + Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1] - Racc_Runtime_Core_Version_R = '1.4.4' - Racc_Runtime_Core_Revision_R = '$raccRevision: 1.4 $'.split[1] + Racc_Runtime_Core_Version_R = '1.4.5' + Racc_Runtime_Core_Revision_R = '$Revision: 1.7 $'.split[1] begin require 'racc/cparse' - # Racc_Runtime_Core_Version_C = (defined in extension) + # Racc_Runtime_Core_Version_C = (defined in extention) Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2] unless new.respond_to?(:_racc_do_parse_c, true) raise LoadError, 'old cparse.so' @@ -121,7 +116,7 @@ module Racc raise NotImplementedError, "#{self.class}\#next_token is not defined" end - def _racc_do_parse_rb( arg, in_debug ) + def _racc_do_parse_rb(arg, in_debug) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, @@ -166,11 +161,11 @@ module Racc ### yyparse ### - def yyparse( recv, mid ) + def yyparse(recv, mid) __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup(), true) end - def _racc_yyparse_rb( recv, mid, arg, c_debug ) + def _racc_yyparse_rb(recv, mid, arg, c_debug) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, @@ -189,7 +184,6 @@ module Racc end end recv.__send__(mid) do |tok, val| -# $stderr.puts "rd: tok=#{tok}, val=#{val}" unless tok @racc_t = 0 else @@ -203,12 +197,7 @@ module Racc act = action_table[i] and action_check[i] == @racc_state[-1] act = action_default[@racc_state[-1]] -# $stderr.puts "02: act=#{act}" -# $stderr.puts "curstate=#{@racc_state[-1]}" - else -# $stderr.puts "01: act=#{act}" end - while act = _racc_evalact(act, arg) ; end @@ -221,9 +210,6 @@ module Racc act = action_table[i] and action_check[i] == @racc_state[-1] act = action_default[@racc_state[-1]] -# $stderr.puts "04: act=#{act}" - else -# $stderr.puts "03: act=#{act}" end while act = _racc_evalact(act, arg) ; @@ -237,13 +223,12 @@ module Racc ### common ### - def _racc_evalact( act, arg ) -# $stderr.puts "ea: act=#{act}" + def _racc_evalact(act, arg) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, reduce_n, use_result, * = arg -nerr = 0 # tmp + nerr = 0 # tmp if act > 0 and act < shift_n # @@ -276,7 +261,7 @@ nerr = 0 # tmp when 2 # yyaccept return shift_n else - raise RuntimeError, '[Racc Bug] unknown jump code' + raise '[Racc Bug] unknown jump code' end end @@ -314,7 +299,6 @@ nerr = 0 # tmp break end end - throw :racc_end_parse, nil if @racc_state.size <= 1 @racc_state.pop @racc_vstack.pop @@ -326,7 +310,7 @@ nerr = 0 # tmp return act else - raise RuntimeError, "[Racc Bug] unknown action #{act.inspect}" + raise "[Racc Bug] unknown action #{act.inspect}" end racc_next_state(@racc_state[-1], @racc_state) if @yydebug @@ -334,7 +318,7 @@ nerr = 0 # tmp nil end - def _racc_do_reduce( arg, act ) + def _racc_do_reduce(arg, act) action_table, action_check, action_default, action_pointer, goto_table, goto_check, goto_default, goto_pointer, nt_base, reduce_table, token_table, shift_n, @@ -375,7 +359,7 @@ nerr = 0 # tmp goto_default[k1] end - def on_error( t, val, vstack ) + def on_error(t, val, vstack) raise ParseError, sprintf("\nparse error on value %s (%s)", val.inspect, token_to_str(t) || '?') end @@ -396,20 +380,20 @@ nerr = 0 # tmp # for debugging output # - def racc_read_token( t, tok, val ) + def racc_read_token(t, tok, val) @racc_debug_out.print 'read ' @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' @racc_debug_out.puts val.inspect @racc_debug_out.puts end - def racc_shift( tok, tstack, vstack ) + def racc_shift(tok, tstack, vstack) @racc_debug_out.puts "shift #{racc_token2str tok}" racc_print_stacks tstack, vstack @racc_debug_out.puts end - def racc_reduce( toks, sim, tstack, vstack ) + def racc_reduce(toks, sim, tstack, vstack) out = @racc_debug_out out.print 'reduce ' if toks.empty? @@ -428,20 +412,20 @@ nerr = 0 # tmp @racc_debug_out.puts end - def racc_e_pop( state, tstack, vstack ) + def racc_e_pop(state, tstack, vstack) @racc_debug_out.puts 'error recovering mode: pop token' racc_print_states state racc_print_stacks tstack, vstack @racc_debug_out.puts end - def racc_next_state( curstate, state ) + def racc_next_state(curstate, state) @racc_debug_out.puts "goto #{curstate}" racc_print_states state @racc_debug_out.puts end - def racc_print_stacks( t, v ) + def racc_print_stacks(t, v) out = @racc_debug_out out.print ' [' t.each_index do |i| @@ -450,34 +434,37 @@ nerr = 0 # tmp out.puts ' ]' end - def racc_print_states( s ) + def racc_print_states(s) out = @racc_debug_out out.print ' [' s.each {|st| out.print ' ', st } out.puts ' ]' end - def racc_token2str( tok ) + def racc_token2str(tok) self.class::Racc_token_to_s_table[tok] or - raise RuntimeError, "[Racc Bug] can't convert token #{tok} to string" + raise "[Racc Bug] can't convert token #{tok} to string" end - def token_to_str( t ) + def token_to_str(t) self.class::Racc_token_to_s_table[t] end end end -..end /usr/lib/ruby/1.8/racc/parser.rb modeval..id1306b79176 -end # end of racc/parser.rb +..end racc/parser.rb modeval..id5256434e8a +end +###### racc/parser.rb end module Nagios class Parser < Racc::Parser -module_eval <<'..end grammar.ry modeval..id458299781d', 'grammar.ry', 57 +module_eval <<'..end grammar.ry modeval..idcb2ea30b34', 'grammar.ry', 57 + +class ::Nagios::Parser::SyntaxError < RuntimeError; end def parse(src) @src = src @@ -490,12 +477,7 @@ def parse(src) @line = 0 @yydebug = true - begin - do_parse - rescue SyntaxError - $stderr.print "#{$!}\n" - exit - end + do_parse end # The lexer. Very simple. @@ -607,12 +589,12 @@ def on_error(token, value, vstack ) if token == '$end'.intern puts "okay, this is silly" else - raise SyntaxError, msg + raise ::Nagios::Parser::SyntaxError, msg end end -..end grammar.ry modeval..id458299781d +..end grammar.ry modeval..idcb2ea30b34 -##### racc 1.4.4 generates ### +##### racc 1.4.5 generates ### racc_reduce_table = [ 0, 0, :racc_error, diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb index 0fccbca75..8f09aa922 100644 --- a/lib/puppet/parser/ast/astarray.rb +++ b/lib/puppet/parser/ast/astarray.rb @@ -30,9 +30,10 @@ class Puppet::Parser::AST items << child end } + rets = items.flatten.collect { |child| child.safeevaluate(scope) - }.flatten + } return rets.reject { |o| o.nil? } end diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb index 1a07fc585..d222893b3 100644 --- a/lib/puppet/parser/ast/resource.rb +++ b/lib/puppet/parser/ast/resource.rb @@ -18,34 +18,34 @@ class Resource < AST::ResourceReference param.safeevaluate(scope) } - objtitles = @title.safeevaluate(scope) + resource_titles = @title.safeevaluate(scope) # it's easier to always use an array, even for only one name - unless objtitles.is_a?(Array) - objtitles = [objtitles] + unless resource_titles.is_a?(Array) + resource_titles = [resource_titles] end - objtype = qualified_type(scope) + resource_type = qualified_type(scope) + + # 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* + # :exported, in which case it clobbers :exported if :exported + # 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. - objtitles.collect { |objtitle| + resource_titles.flatten.collect { |resource_title| exceptwrap :type => Puppet::ParseError do - exp = self.exported || scope.resource.exported? - # 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* - # :exported, in which case it clobbers :exported if :exported - # is true. Argh, this was a very tough one to track down. - virt = self.virtual || scope.resource.virtual? || exp - obj = Puppet::Parser::Resource.new( - :type => objtype, - :title => objtitle, + resource = Puppet::Parser::Resource.new( + :type => resource_type, + :title => resource_title, :params => paramobjects, :file => self.file, :line => self.line, - :exported => exp, + :exported => self.exported, :virtual => virt, :source => scope.source, :scope => scope @@ -53,11 +53,11 @@ class Resource < AST::ResourceReference # And then store the resource in the compiler. # At some point, we need to switch all of this to return - # objects instead of storing them like this. - scope.compiler.add_resource(scope, obj) - obj + # resources instead of storing them like this. + scope.compiler.add_resource(scope, resource) + resource end - }.reject { |obj| obj.nil? } + }.reject { |resource| resource.nil? } end # Set the parameters for our object. diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb index fb7d95c52..9423db26b 100644 --- a/lib/puppet/parser/collector.rb +++ b/lib/puppet/parser/collector.rb @@ -72,8 +72,7 @@ class Puppet::Parser::Collector def collect_exported # First get everything from the export table. Just reuse our # collect_virtual method but tell it to use 'exported? for the test. - resources = collect_virtual(true).reject { |r| ! r.virtual? }.each { |r| r.exported = false } - #resources = collect_virtual(true).reject { |r| ! r.virtual? } + resources = collect_virtual(true).reject { |r| ! r.virtual? } count = resources.length diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb index 1bdde234e..6aff19d29 100644 --- a/lib/puppet/parser/functions/realize.rb +++ b/lib/puppet/parser/functions/realize.rb @@ -8,7 +8,7 @@ Puppet::Parser::Functions::newfunction(:realize, :doc => "Make a virtual object reference; e.g.: ``realize User[luke]``." ) do |vals| coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual) vals = [vals] unless vals.is_a?(Array) - coll.resources = vals + coll.resources = vals.flatten compiler.add_collection(coll) end diff --git a/lib/puppet/provider/naginator.rb b/lib/puppet/provider/naginator.rb index 8e8a3d65e..233d82eb6 100644 --- a/lib/puppet/provider/naginator.rb +++ b/lib/puppet/provider/naginator.rb @@ -23,7 +23,11 @@ class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile end def self.parse(text) - Nagios::Parser.new.parse(text) + begin + Nagios::Parser.new.parse(text) + rescue => detail + raise Puppet::Error, "Could not parse configuration for %s: %s" % [resource_type.name, detail] + end end def self.to_file(records) diff --git a/lib/puppet/provider/parsedfile.rb b/lib/puppet/provider/parsedfile.rb index b4a4a3b91..a4c4bc87c 100755 --- a/lib/puppet/provider/parsedfile.rb +++ b/lib/puppet/provider/parsedfile.rb @@ -108,10 +108,11 @@ class Puppet::Provider::ParsedFile < Puppet::Provider # Return a list of all of the records we can find. def self.instances - prefetch() - @records.find_all { |r| r[:record_type] == self.name }.collect { |r| - new(r) - } + targets.collect do |target| + prefetch_target(target) + end.flatten.reject { |r| skip_record?(r) }.collect do |record| + new(record) + end end # Override the default method with a lot more functionality. @@ -171,31 +172,39 @@ class Puppet::Provider::ParsedFile < Puppet::Provider # resource instance. def self.prefetch(resources = nil) # Reset the record list. - @records = [] - targets(resources).each do |target| - @records += prefetch_target(target) - end + @records = prefetch_all_targets(resources) - if resources - matchers = resources.dup - @records.each do |record| - # Skip things like comments and blank lines - next if skip_record?(record) + match_providers_with_resources(resources) + end - if name = record[:name] and resource = resources[name] + def self.match_providers_with_resources(resources) + return unless resources + matchers = resources.dup + @records.each do |record| + # Skip things like comments and blank lines + next if skip_record?(record) + + if name = record[:name] and resource = resources[name] + resource.provider = new(record) + elsif respond_to?(:match) + if resource = match(record, matchers) + # Remove this resource from circulation so we don't unnecessarily try to match + matchers.delete(resource.title) + record[:name] = resource[:name] resource.provider = new(record) - elsif respond_to?(:match) - if resource = match(record, matchers) - # Remove this resource from circulation so we don't unnecessarily try to match - matchers.delete(resource.title) - record[:name] = resource[:name] - resource.provider = new(record) - end end end end end + def self.prefetch_all_targets(resources) + records = [] + targets(resources).each do |target| + records += prefetch_target(target) + end + records + end + # Prefetch an individual target. def self.prefetch_target(target) target_records = retrieve(target).each do |r| @@ -217,6 +226,7 @@ class Puppet::Provider::ParsedFile < Puppet::Provider # Is there an existing record with this name? def self.record?(name) + return nil unless @records @records.find { |r| r[:name] == name } end @@ -367,4 +377,3 @@ class Puppet::Provider::ParsedFile < Puppet::Provider end end end - diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index f8aa701f0..706ea1386 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -715,10 +715,6 @@ class Type end end - if p = self.provider and p.respond_to?(:prefetch) - p.prefetch - end - # this only operates on properties, not properties + children # it's important that we call retrieve() on the type instance, # not directly on the property, because it allows the type to override diff --git a/lib/puppet/type/file/selcontext.rb b/lib/puppet/type/file/selcontext.rb index 8ef51366a..717f58805 100644 --- a/lib/puppet/type/file/selcontext.rb +++ b/lib/puppet/type/file/selcontext.rb @@ -44,6 +44,14 @@ module Puppet return property_default end + def insync?(value) + if not selinux_support? + debug("SELinux bindings not found. Ignoring parameter.") + return true + end + super + end + def sync self.set_selinux_context(@resource[:path], @should, name) return :file_changed diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index 492dd6136..074afb6b2 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -100,6 +100,8 @@ module Puppet end def insync?(is) + return true unless self.should + # We know the 'is' is a number, so we need to convert the 'should' to a number, # too. @should.each do |value| @@ -142,6 +144,10 @@ module Puppet newproperty(:password, :required_features => :manages_passwords) do desc "The user's password, in whatever encrypted format the local machine requires. Be sure to enclose any value that includes a dollar sign ($) in single quotes (\')." + validate do |value| + raise ArgumentError, "Passwords cannot include ':'" if value.include?(":") + end + def change_to_s(currentvalue, newvalue) if currentvalue == :absent return "created password" diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb index 1e917793b..4f7b26b8a 100644 --- a/lib/puppet/type/yumrepo.rb +++ b/lib/puppet/type/yumrepo.rb @@ -178,7 +178,10 @@ module Puppet # Store all modifications back to disk def self.store - inifile.store + file = inifile.store + unless file.nil? + File.chmod(0644, file) + end end # This is only used during testing. diff --git a/lib/puppet/util/inifile.rb b/lib/puppet/util/inifile.rb index 9f5582e95..f5fab8530 100644 --- a/lib/puppet/util/inifile.rb +++ b/lib/puppet/util/inifile.rb @@ -163,6 +163,7 @@ module Puppet::Util::IniConfig end if dirty Puppet::Util::FileType.filetype(:flat).new(file).write(text) + return file end end end diff --git a/lib/puppet/util/nagios_maker.rb b/lib/puppet/util/nagios_maker.rb index a7aae4e70..316334929 100644 --- a/lib/puppet/util/nagios_maker.rb +++ b/lib/puppet/util/nagios_maker.rb @@ -42,6 +42,7 @@ module Puppet::Util::NagiosMaker target = "/etc/nagios/#{full_name.to_s}.cfg" provider = type.provide(:naginator, :parent => Puppet::Provider::Naginator, :default_target => target) {} + provider.nagios_type type.desc "The Nagios type #{name.to_s}. This resource type is autogenerated using the model developed in Naginator_, and all of the Nagios types are generated using the @@ -51,6 +52,9 @@ module Puppet::Util::NagiosMaker files. By default, the statements will be added to ``#{target}``, but you can send them to a different file by setting their ``target`` attribute. + You can purge Nagios resources using the ``resources`` type, but *only* + in the default file locations. This is an architectural limitation. + .. _naginator: http://reductivelabs.com/trac/naginator " end diff --git a/spec/unit/other/transaction.rb b/spec/unit/other/transaction.rb deleted file mode 100755 index d2ac26869..000000000 --- a/spec/unit/other/transaction.rb +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env ruby - -require File.dirname(__FILE__) + '/../../spec_helper' - -require 'puppet/transaction' - -describe Puppet::Transaction, " when determining tags" do - before do - @config = Puppet::Resource::Catalog.new - @transaction = Puppet::Transaction.new(@config) - end - - it "should default to the tags specified in the :tags setting" do - Puppet.expects(:[]).with(:tags).returns("one") - @transaction.tags.should == %w{one} - end - - it "should split tags based on ','" do - Puppet.expects(:[]).with(:tags).returns("one,two") - @transaction.tags.should == %w{one two} - end - - it "should use any tags set after creation" do - Puppet.expects(:[]).with(:tags).never - @transaction.tags = %w{one two} - @transaction.tags.should == %w{one two} - end - - it "should always convert assigned tags to an array" do - @transaction.tags = "one::two" - @transaction.tags.should == %w{one::two} - end -end diff --git a/spec/unit/parser/ast/astarray.rb b/spec/unit/parser/ast/astarray.rb index f1c28ce47..b3026fe1e 100755 --- a/spec/unit/parser/ast/astarray.rb +++ b/spec/unit/parser/ast/astarray.rb @@ -49,7 +49,7 @@ describe Puppet::Parser::AST::ASTArray do operator.evaluate(@scope).should == [123] end - it "should flatten the results of children evaluation" do + 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) @@ -59,7 +59,7 @@ describe Puppet::Parser::AST::ASTArray do item1.expects(:safeevaluate).with(@scope).returns([123]) operator = Puppet::Parser::AST::ASTArray.new :children => [item2] - operator.evaluate(@scope).should == [123] + operator.evaluate(@scope).should == [[123]] end diff --git a/spec/unit/parser/ast/resource.rb b/spec/unit/parser/ast/resource.rb new file mode 100755 index 000000000..b257cb116 --- /dev/null +++ b/spec/unit/parser/ast/resource.rb @@ -0,0 +1,103 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::Resource do + ast = Puppet::Parser::AST + + before :each do + @title = stub_everything 'title' + @compiler = stub_everything 'compiler' + @scope = Puppet::Parser::Scope.new(:compiler => @compiler) + @param1 = stub_everything 'parameter', :is_a? => true + @scope.stubs(:resource).returns(stub_everything) + @params = ast::ASTArray.new( :children => [@param1]) + @resource = ast::Resource.new(:title => @title, :type => "Resource", :params => @params ) + @resource.stubs(:qualified_type).returns("Resource") + Puppet::Parser::Resource.stubs(:new).returns(stub_everything) + end + + it "should evaluate all its parameters" do + @param1.expects(:safeevaluate).with(@scope) + + @resource.evaluate(@scope) + end + + it "should evaluate its title" do + + @title.expects(:safeevaluate).with(@scope) + + @resource.evaluate(@scope) + end + + it "should flatten the titles array" do + titles = stub 'titles' + title_array = stub 'title_array', :is_a? => true + + titles.stubs(:safeevaluate).with(@scope).returns(title_array) + + title_array.expects(:flatten).returns([]) + + @resource.title = titles + @resource.evaluate(@scope) + end + + it "should create one resource objects per title" do + titles = stub 'titles' + title_array = stub 'title_array', :is_a? => true + + title_array.stubs(:flatten).returns([@title]) + titles.stubs(:safeevaluate).with(@scope).returns(title_array) + + Puppet::Parser::Resource.expects(:new).with { |hash| hash[:title] == @title } + + @resource.title = titles + @resource.evaluate(@scope) + end + + it "should handover resources to the compiler" do + resource = stub 'resource' + titles = stub 'titles' + title_array = stub 'title_array', :is_a? => true + + title_array.stubs(:flatten).returns([@title]) + titles.stubs(:safeevaluate).with(@scope).returns(title_array) + Puppet::Parser::Resource.stubs(:new).returns(resource) + + @compiler.expects(:add_resource).with(@scope, resource) + + @resource.title = titles + @resource.evaluate(@scope) + end + + it "should return the newly created resources" do + resource = stub 'resource' + titles = stub 'titles' + title_array = stub 'title_array', :is_a? => true + + title_array.stubs(:flatten).returns([@title]) + titles.stubs(:safeevaluate).with(@scope).returns(title_array) + Puppet::Parser::Resource.stubs(:new).returns(resource) + + @compiler.stubs(:add_resource).with(resource) + + @resource.title = titles + @resource.evaluate(@scope).should == [resource] + end + + it "should generate virtual resources if it is virtual" do + @resource.virtual = true + + Puppet::Parser::Resource.expects(:new).with { |hash| hash[:virtual] == true } + + @resource.evaluate(@scope) + end + + it "should generate virtual and exported resources if it is exported" do + @resource.exported = true + + Puppet::Parser::Resource.expects(:new).with { |hash| hash[:virtual] == true and hash[:exported] == true } + + @resource.evaluate(@scope) + end +end diff --git a/spec/unit/parser/collector.rb b/spec/unit/parser/collector.rb index edd74e25f..f92b881c8 100755 --- a/spec/unit/parser/collector.rb +++ b/spec/unit/parser/collector.rb @@ -240,10 +240,10 @@ describe Puppet::Parser::Collector, "when collecting exported resources" do one = stub 'one', :type => "Mytype", :virtual? => true, :exported? => true two = stub 'two', :type => "Mytype", :virtual? => true, :exported? => true - one.expects(:exported=).with(false) - one.expects(:virtual=).with(false) - two.expects(:exported=).with(false) - two.expects(:virtual=).with(false) + one.stubs(:exported=) + one.stubs(:virtual=) + two.stubs(:exported=) + two.stubs(:virtual=) @compiler.expects(:resources).returns([one, two]) diff --git a/spec/unit/parser/functions/realize.rb b/spec/unit/parser/functions/realize.rb new file mode 100755 index 000000000..d9c94b143 --- /dev/null +++ b/spec/unit/parser/functions/realize.rb @@ -0,0 +1,51 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe "the realize function" do + + before :each do + @collector = stub_everything 'collector' + @scope = Puppet::Parser::Scope.new() + @compiler = stub 'compiler' + @compiler.stubs(:add_collection).with(@collector) + @scope.stubs(:compiler).returns(@compiler) + end + + it "should exist" do + Puppet::Parser::Functions.function("realize").should == "function_realize" + end + + it "should create a Collector when called" do + + Puppet::Parser::Collector.expects(:new).returns(@collector) + + @scope.function_realize("test") + end + + it "should assign the passed-in resources to the collector" do + Puppet::Parser::Collector.stubs(:new).returns(@collector) + + @collector.expects(:resources=).with(["test"]) + + @scope.function_realize("test") + end + + it "should flatten the resources assigned to the collector" do + Puppet::Parser::Collector.stubs(:new).returns(@collector) + + @collector.expects(:resources=).with(["test"]) + + @scope.function_realize([["test"]]) + end + + it "should let the compiler know this collector" do + Puppet::Parser::Collector.stubs(:new).returns(@collector) + @collector.stubs(:resources=).with(["test"]) + + @compiler.expects(:add_collection).with(@collector) + + @scope.function_realize("test") + end + +end diff --git a/spec/unit/provider/naginator.rb b/spec/unit/provider/naginator.rb new file mode 100644 index 000000000..d0d43aa4b --- /dev/null +++ b/spec/unit/provider/naginator.rb @@ -0,0 +1,58 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/provider/naginator' + +describe Puppet::Provider::Naginator do + before do + @resource_type = stub 'resource_type', :name => :nagios_test + @class = Class.new(Puppet::Provider::Naginator) + + @class.stubs(:resource_type).returns @resource_type + end + + it "should be able to look up the associated Nagios type" do + nagios_type = mock "nagios_type" + nagios_type.stubs :attr_accessor + Nagios::Base.expects(:type).with(:test).returns nagios_type + + @class.nagios_type.should equal(nagios_type) + end + + it "should use the Nagios type to determine whether an attribute is valid" do + nagios_type = mock "nagios_type" + nagios_type.stubs :attr_accessor + Nagios::Base.expects(:type).with(:test).returns nagios_type + + nagios_type.expects(:parameters).returns [:foo, :bar] + + @class.valid_attr?(:test, :foo).should be_true + end + + it "should use Naginator to parse configuration snippets" do + parser = mock 'parser' + parser.expects(:parse).with("my text").returns "my instances" + Nagios::Parser.expects(:new).returns(parser) + + @class.parse("my text").should == "my instances" + end + + it "should join Nagios::Base records with '\\n' when asked to convert them to text" do + @class.expects(:header).returns "myheader\n" + + @class.to_file([:one, :two]).should == "myheader\none\ntwo" + end + + it "should be able to prefetch instance from configuration files" do + @class.should respond_to(:prefetch) + end + + it "should be able to generate a list of instances" do + @class.should respond_to(:instances) + end + + it "should never skip records" do + @class.should_not be_skip_record("foo") + end +end diff --git a/spec/unit/provider/parsedfile.rb b/spec/unit/provider/parsedfile.rb new file mode 100755 index 000000000..05e9de3ab --- /dev/null +++ b/spec/unit/provider/parsedfile.rb @@ -0,0 +1,50 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../spec_helper' + +require 'puppet/provider/parsedfile' + +# Most of the tests for this are still in test/ral/provider/parsedfile.rb. +describe Puppet::Provider::ParsedFile do + before do + @class = Class.new(Puppet::Provider::ParsedFile) + end + + describe "when looking up records loaded from disk" do + it "should return nil if no records have been loaded" do + @class.record?("foo").should be_nil + end + end + + describe "when generating a list of instances" do + it "should return an instance for each record parsed from all of the registered targets" do + @class.expects(:targets).returns %w{/one /two} + @class.stubs(:skip_record?).returns false + one = [:uno1, :uno2] + two = [:dos1, :dos2] + @class.expects(:prefetch_target).with("/one").returns one + @class.expects(:prefetch_target).with("/two").returns two + + results = [] + (one + two).each do |inst| + results << inst.to_s + "_instance" + @class.expects(:new).with(inst).returns(results[-1]) + end + + @class.instances.should == results + end + + it "should skip specified records" do + @class.expects(:targets).returns %w{/one} + @class.expects(:skip_record?).with(:uno).returns false + @class.expects(:skip_record?).with(:dos).returns true + one = [:uno, :dos] + @class.expects(:prefetch_target).returns one + + @class.expects(:new).with(:uno).returns "eh" + @class.expects(:new).with(:dos).never + + @class.instances + end + end +end diff --git a/spec/unit/transaction.rb b/spec/unit/transaction.rb index 2aa0df37b..554d20ce9 100755 --- a/spec/unit/transaction.rb +++ b/spec/unit/transaction.rb @@ -1,212 +1,33 @@ -#!/usr/bin/env ruby" +#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../spec_helper' require 'puppet/transaction' -describe Puppet::Transaction do +describe Puppet::Transaction, " when determining tags" do before do - @generator_class = mkgenerator - @generator = mkgenerator.new(:name => "foo") - - @catalog = Puppet::Resource::Catalog.new - @catalog.add_resource @generator - - @report = stub_everything 'report' - Puppet::Transaction::Report.stubs(:new).returns(@report) - - @transaction = Puppet::Transaction.new(@catalog) + @config = Puppet::Resource::Catalog.new + @transaction = Puppet::Transaction.new(@config) end - after do - Puppet::Type.rmtype(:generator) + it "should default to the tags specified in the :tags setting" do + Puppet.expects(:[]).with(:tags).returns("one") + @transaction.tags.should == %w{one} end - describe "when generating resources" do - - it "should call the generate() method on all resources" do - @generator.expects(:generate) - @transaction.generate - end - - it "should add all generated resources to the catalog" do - one = @generator_class.new :name => "one" - two = @generator_class.new :name => "two" - @generator.expects(:generate).returns [one, two] - @transaction.generate - - @catalog.resource(:generator, "one").should equal(one) - @catalog.resource(:generator, "two").should equal(two) - end - - it "should generate and add resources from the generated resources" do - one = @generator_class.new :name => "one" - two = @generator_class.new :name => "two" - @generator.expects(:generate).returns [one] - one.expects(:generate).returns [two] - @transaction.generate - - @catalog.resource(:generator, "two").should equal(two) - end - - it "should add an edge in the relationship graph between the generating and generated resource" do - one = @generator_class.new :name => "one" - two = @generator_class.new :name => "two" - @generator.expects(:generate).returns [one] - one.expects(:generate).returns [two] - @transaction.generate - - @catalog.relationship_graph.should be_edge(@generator, one) - @catalog.relationship_graph.should be_edge(one, two) - end - - it "should finish all non-conflicting resources" do - one = @generator_class.new :name => "one" - one.expects(:finish) - @generator.expects(:generate).returns [one] - @transaction.generate - end - - describe "mid-transaction" do - it "should call the eval_generate() method on the resource" do - @generator.expects(:eval_generate) - @transaction.eval_generate(@generator) - end - - it "should add all generated resources to the catalog" do - one = @generator_class.new :name => "one" - two = @generator_class.new :name => "two" - @generator.expects(:eval_generate).returns [one, two] - @transaction.eval_generate(@generator) - - @catalog.resource(:generator, "one").should equal(one) - @catalog.resource(:generator, "two").should equal(two) - end - - it "should add an edge in the relationship graph between the generating and generated resource" do - one = @generator_class.new :name => "one" - @generator.expects(:eval_generate).returns [one] - @transaction.eval_generate(@generator) - - @catalog.relationship_graph.should be_edge(@generator, one) - end - - it "should not recursively eval_generate resources" do - one = @generator_class.new :name => "one" - two = @generator_class.new :name => "two" - @generator.expects(:eval_generate).returns [one] - one.expects(:eval_generate).never - @transaction.eval_generate(@generator) - end - - it "should finish all non-conflicting resources" do - one = @generator_class.new :name => "one" - one.expects(:finish) - @generator.expects(:eval_generate).returns [one] - @transaction.eval_generate(@generator) - end - end - + it "should split tags based on ','" do + Puppet.expects(:[]).with(:tags).returns("one,two") + @transaction.tags.should == %w{one two} end - describe "when generating a report" do - - before :each do - Puppet.stubs(:[]).with(:report).returns(true) - end - - it "should create a Puppet::Transaction::Report when the Transaction is created" do - Puppet::Transaction::Report.expects(:new).returns(@report) - - Puppet::Transaction.new(@catalog) - end - - it "should return a Puppet::Transaction::Report" do - @transaction.generate_report.should == @report - end - - it "should have a metric for resources" do - @report.expects(:newmetric).with { |metric,hash| metric == :resources } - - @transaction.generate_report - end - - it "should have a metric for time" do - @report.expects(:newmetric).with { |metric,hash| metric == :time } - - @transaction.generate_report - end - - it "should have a metric for changes" do - @report.expects(:newmetric).with { |metric,hash| metric == :changes } - - @transaction.generate_report - end - - it "should store the current time" do - now = stub 'time' - Time.stubs(:now).returns(now) - - @report.expects(:time=).with(now) - - @transaction.generate_report - end - - end - - describe "when sending a report" do - - before :each do - @transaction.stubs(:generate_report).returns(@report) - Puppet.stubs(:[]).with(:report).returns(true) - Puppet.stubs(:[]).with(:rrdgraph).returns(false) - Puppet.stubs(:[]).with(:summarize).returns(false) - end - - it "should ask the transaction for a report" do - @transaction.expects(:generate_report) - - @transaction.send_report - end - - it "should ask the report for a graph if rrdgraph is enable" do - Puppet.stubs(:[]).with(:rrdgraph).returns(true) - - @report.expects(:graph) - - @transaction.send_report - end - - - it "should call report.save" do - @report.expects(:save) - - @transaction.send_report - end - + it "should use any tags set after creation" do + Puppet.expects(:[]).with(:tags).never + @transaction.tags = %w{one two} + @transaction.tags.should == %w{one two} end - def mkgenerator - # Create a bogus type that generates new instances with shorter names - type = Puppet::Type.newtype(:generator) do - newparam(:name, :namevar => true) - - # Stub methods. - def generate - end - - def eval_generate - end - - def finished? - @finished - end - - def finish - @finished = true - end - end - - return type + it "should always convert assigned tags to an array" do + @transaction.tags = "one::two" + @transaction.tags.should == %w{one::two} end end diff --git a/spec/unit/type/file/selinux.rb b/spec/unit/type/file/selinux.rb index c81270ab0..bf3315bf9 100644 --- a/spec/unit/type/file/selinux.rb +++ b/spec/unit/type/file/selinux.rb @@ -73,6 +73,12 @@ Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f @sel.expects(:set_selinux_context).with("/my/file", ["newone"], param) @sel.sync end + + it "should do nothing for insync? if no SELinux support" do + @sel.should = %{newcontext} + @sel.expects(:selinux_support?).returns false + @sel.insync?("oldcontext").should == true + end end end diff --git a/spec/unit/type/user.rb b/spec/unit/type/user.rb index 5d84591da..2e8616ce8 100755 --- a/spec/unit/type/user.rb +++ b/spec/unit/type/user.rb @@ -38,6 +38,10 @@ describe user do it "should have a valid provider" do user.new(:name => "foo").provider.class.ancestors.should be_include(Puppet::Provider) end + + it "should fail if a ':' is included in the password" do + lambda { user.create(:name => "foo", :password => 'some:thing') }.should raise_error(Puppet::Error) + end end properties = [:ensure, :uid, :gid, :home, :comment, :shell, :password, :groups, :roles, :auths, :profiles, :project, :keys] @@ -179,6 +183,12 @@ describe user do @gid = user.attrclass(:gid).new(:resource => @resource, :should => %w{foo bar}) end + it "should return true if no 'should' values are set" do + @gid = user.attrclass(:gid).new(:resource => @resource) + + @gid.must be_insync(500) + end + it "should return true if any of the specified groups are equal to the current integer" do Puppet::Util.expects(:gid).with("foo").returns 300 Puppet::Util.expects(:gid).with("bar").returns 500 diff --git a/spec/unit/util/nagios_maker.rb b/spec/unit/util/nagios_maker.rb index b75439400..1e1aefcae 100755 --- a/spec/unit/util/nagios_maker.rb +++ b/spec/unit/util/nagios_maker.rb @@ -13,6 +13,9 @@ describe Puppet::Util::NagiosMaker do @nagtype = stub 'nagios type', :parameters => [], :namevar => :name Nagios::Base.stubs(:type).with(:test).returns(@nagtype) + + @provider = stub 'provider', :nagios_type => nil + @type = stub 'type', :newparam => nil, :newproperty => nil, :provide => @provider, :desc => nil, :ensurable => nil end it "should be able to create a new nagios type" do @@ -26,73 +29,59 @@ describe Puppet::Util::NagiosMaker do end it "should create a new RAL type with the provided name prefixed with 'nagios_'" do - type = stub 'type', :newparam => nil, :newproperty => nil, :ensurable => nil, :provide => nil, :desc => nil - - Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should mark the created type as ensurable" do - type = stub 'type', :newparam => nil, :newproperty => nil, :provide => nil, :desc => nil + @type.expects(:ensurable) - type.expects(:ensurable) - - Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should create a namevar parameter for the nagios type's name parameter" do - type = stub 'type', :newproperty => nil, :ensurable => nil, :provide => nil, :desc => nil - - type.expects(:newparam).with(:name, :namevar => true) + @type.expects(:newparam).with(:name, :namevar => true) - Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should create a property for all non-namevar parameters" do - type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil, :desc => nil - @nagtype.stubs(:parameters).returns([:one, :two]) - type.expects(:newproperty).with(:one) - type.expects(:newproperty).with(:two) - type.expects(:newproperty).with(:target) + @type.expects(:newproperty).with(:one) + @type.expects(:newproperty).with(:two) + @type.expects(:newproperty).with(:target) - Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should skip parameters that start with integers" do - type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil, :desc => nil - @nagtype.stubs(:parameters).returns(["2dcoords".to_sym, :other]) - type.expects(:newproperty).with(:other) - type.expects(:newproperty).with(:target) + @type.expects(:newproperty).with(:other) + @type.expects(:newproperty).with(:target) - Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should deduplicate the parameter list" do - type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil, :desc => nil - @nagtype.stubs(:parameters).returns([:one, :one]) - type.expects(:newproperty).with(:one) - type.expects(:newproperty).with(:target) + @type.expects(:newproperty).with(:one) + @type.expects(:newproperty).with(:target) - Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end it "should create a target property" do - type = stub 'type', :newparam => nil, :ensurable => nil, :provide => nil, :desc => nil + @type.expects(:newproperty).with(:target) - type.expects(:newproperty).with(:target) - - Puppet::Type.expects(:newtype).with(:nagios_test).returns(type) + Puppet::Type.expects(:newtype).with(:nagios_test).returns(@type) @module.create_nagios_type(:test) end end @@ -100,6 +89,7 @@ end describe Puppet::Util::NagiosMaker, " when creating the naginator provider" do before do @module = Puppet::Util::NagiosMaker + @provider = stub 'provider', :nagios_type => nil @nagtype = stub 'nagios type', :parameters => [], :namevar => :name Nagios::Base.stubs(:type).with(:test).returns(@nagtype) @@ -109,19 +99,27 @@ describe Puppet::Util::NagiosMaker, " when creating the naginator provider" do end it "should add a naginator provider" do - @type.expects(:provide).with { |name, options| name == :naginator } + @type.expects(:provide).with { |name, options| name == :naginator }.returns @provider @module.create_nagios_type(:test) end it "should set Puppet::Provider::Naginator as the parent class of the provider" do - @type.expects(:provide).with { |name, options| options[:parent] == Puppet::Provider::Naginator } + @type.expects(:provide).with { |name, options| options[:parent] == Puppet::Provider::Naginator }.returns @provider @module.create_nagios_type(:test) end it "should use /etc/nagios/$name.cfg as the default target" do - @type.expects(:provide).with { |name, options| options[:default_target] == "/etc/nagios/nagios_test.cfg" } + @type.expects(:provide).with { |name, options| options[:default_target] == "/etc/nagios/nagios_test.cfg" }.returns @provider + + @module.create_nagios_type(:test) + end + + it "should trigger the lookup of the Nagios class" do + @type.expects(:provide).returns @provider + + @provider.expects(:nagios_type) @module.create_nagios_type(:test) end diff --git a/tasks/rake/redlabpackage.rb b/tasks/rake/redlabpackage.rb new file mode 100644 index 000000000..2de8005b6 --- /dev/null +++ b/tasks/rake/redlabpackage.rb @@ -0,0 +1,265 @@ +#!/usr/bin/env ruby + +# A raw platform for creating packages. + +require 'rbconfig' +require 'rake' +require 'rake/tasklib' + +# The PackageTask will create the following targets: +# +# [<b>:clobber_package</b>] +# Delete all the package files. This target is automatically +# added to the main clobber target. +# +# [<b>:repackage</b>] +# Rebuild the package files from scratch, even if they are not out +# of date. +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tgz"</b>] +# Create a gzipped tar package (if <em>need_tar</em> is true). +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.gz"</b>] +# Create a gzipped tar package (if <em>need_tar_gz</em> is true). +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.tar.bz2"</b>] +# Create a bzip2'd tar package (if <em>need_tar_bz2</em> is true). +# +# [<b>"<em>package_dir</em>/<em>name</em>-<em>version</em>.zip"</b>] +# Create a zip package archive (if <em>need_zip</em> is true). +# +# Example: +# +# Rake::PackageTask.new("rake", "1.2.3") do |p| +# p.need_tar = true +# p.package_files.include("lib/**/*.rb") +# end +# +class Rake::RedLabPackageTask < Rake::TaskLib + # The different directory types we can manage. + DIRTYPES = { + :bindir => :bins, + :sbindir => :sbins, + :sitelibdir => :rubylibs + } + + # Name of the package (from the GEM Spec). + attr_accessor :name + + # Version of the package (e.g. '1.3.2'). + attr_accessor :version + + # Directory used to store the package files (default is 'pkg'). + attr_accessor :package_dir + + # The directory to which to publish packages and html and such. + attr_accessor :publishdir + + # The package-specific publishing directory + attr_accessor :pkgpublishdir + + # The Product name. Defaults to a capitalized version of the + # package name + attr_accessor :product + + # The copyright message. + attr_accessor :copyright + + # The vendor. + attr_accessor :vendor + + # The license file. Defaults to COPYING. + attr_accessor :license + + # The readme file. Defaults to README. + attr_accessor :readme + + # The description. + attr_accessor :description + + # The summary. + attr_accessor :summary + + # The directory in which to put the binaries. Defaults to the system + # default. + attr_accessor :bindir + + # The executables. + attr_accessor :bins + + # The directory in which to put the system binaries. Defaults to the + # system default. + attr_accessor :sbindir + + # The system binaries. + attr_accessor :sbins + + # The libraries. + attr_accessor :rubylibs + + # The directory in which to put Ruby libraries. Defaults to the + # system site_dir. + attr_accessor :sitelibdir + + # The URL for the package. + attr_accessor :url + + # The source for the package. + attr_accessor :source + + # Our operating system. + attr_reader :os + + # Add a required package. + def add_dependency(name, version = nil) + @requires[name] = version + end + + # Create the tasks defined by this task library. + def define + fail "Version required (or :noversion)" if @version.nil? + @version = nil if :noversion == @version + + directory pkgdest + file pkgdest => self.package_dir + + directory self.package_dir + + self.mkcopytasks + + self + end + + # Return the list of files associated with a dirname. + def files(dirname) + if @dirtypes.include?(dirname) + return self.send(@dirtypes[dirname]) + else + raise "Could not find directory type %s" % dirname + end + end + + # Create a Package Task with the given name and version. + def initialize(name=nil, version=nil) + # Theoretically, one could eventually add directory types here. + @dirtypes = DIRTYPES.dup + + @requires = {} + + @name = name + @version = version + @package_dir = 'pkg' + @product = name.capitalize + + @bindir = Config::CONFIG["bindir"] + @sbindir = Config::CONFIG["sbindir"] + @sitelibdir = Config::CONFIG["sitelibdir"] + + @license = "COPYING" + @readme = "README" + + yield self if block_given? + + define unless name.nil? + + # Make sure they've provided everything necessary. + %w{copyright vendor description}.each do |attr| + unless self.send(attr) + raise "You must provide the attribute %s" % attr + end + end + end + + # Make tasks for copying/linking all of the necessary files. + def mkcopytasks + basedir = pkgdest() + + tasks = [] + + # Iterate across all of the file locations... + @dirtypes.each do |dirname, filemethod| + tname = ("copy" + dirname.to_s).intern + + dir = self.send(dirname) + + reqs = [] + + # This is where we're putting the files. + targetdir = self.targetdir(dirname) + + # Make sure our target directories exist + directory targetdir + file targetdir => basedir + + # Get the file list and remove the leading directory. + files = self.files(dirname) or next + + reqs = [] + files.each do |sourcefile| + # The file without the basedir. This is necessary because + # files are created with the path from ".", but they often + # have 'lib' changed to 'site_ruby' or something similar. + destfile = File.join(targetdir, sourcefile.sub(/^\w+\//, '')) + reqs << destfile + + # Make sure the base directory is listed as a prereq + sourcedir = File.dirname(sourcefile) + destdir = nil + unless sourcedir == "." + destdir = File.dirname(destfile) + reqs << destdir + directory(destdir) + end + + # Now make the task associated with creating the object in + # question. + if FileTest.directory?(sourcefile) + directory(destfile) + else + file(destfile => sourcefile) do + if FileTest.exists?(destfile) + if File.stat(sourcefile) > File.stat(destfile) + rm_f destfile + safe_ln(sourcefile, destfile) + end + else + safe_ln(sourcefile, destfile) + end + end + + # If we've set the destdir, then list it as a prereq. + if destdir + file destfile => destdir + end + end + end + + # And create a task for each one + task tname => reqs + + # And then mark our task as a prereq + tasks << tname + end + + task :copycode => [self.package_dir, pkgdest] + + task :copycode => tasks do + puts "Finished copying" + end + end + + # Where we're copying a given type of file. + def targetdir(dirname) + File.join(pkgdest(), self.send(dirname)).sub("//", "/") + end + + private + + def package_name + @version ? "#{@name}-#{@version}" : @name + end + + def package_dir_path + "#{package_dir}/#{package_name}" + end +end diff --git a/tasks/rake/reductive.rb b/tasks/rake/reductive.rb new file mode 100644 index 000000000..2fbd2b4d9 --- /dev/null +++ b/tasks/rake/reductive.rb @@ -0,0 +1,538 @@ +#!/usr/bin/env ruby + +# The tasks associated with building Reductive Labs projects + +require 'rbconfig' +require 'rake' +require 'rake/tasklib' + +require 'rake/clean' +require 'rake/testtask' + +$features = {} + +begin + require 'rubygems' + require 'rake/gempackagetask' + $features[:gem] = true +rescue Exception + $features[:gem] = false + $stderr.puts "No Gems; skipping" + nil +end + +begin + require 'rdoc/rdoc' + $features[:rdoc] = true +rescue => detail + $features[:rdoc] = false + puts "No rdoc: %s" % detail +end + +if $features[:rdoc] + require 'rake/rdoctask' +end + +# Create all of the standard targets for a Reductive Labs project. +# NOTE: The reason so many of the rake tasks are generated, rather than being +# declared directly, is that they need information from the project instance. +# Any rake task with an instance variable (e.g., @name or @version) needs +# to have that variable assigned *before* the task is defined. Suckage. +class Rake::RedLabProject < Rake::TaskLib + # The project name. + attr_accessor :name + + # The project version. + attr_accessor :version + + # The directory to which to publish packages and html and such. + attr_accessor :publishdir + + # The package-specific publishing directory + attr_accessor :pkgpublishdir + + # Create a Gem file. + attr_accessor :mkgem + + # The hosts to run all of our tests on. + attr_accessor :testhosts + + # The summary of this project. + attr_accessor :summary + + # The description of this project. + attr_accessor :description + + # The author of this project. + attr_accessor :author + + # A Contact email address. + attr_accessor :email + + # The URL for the project. + attr_accessor :url + + # Where to get the source code. + attr_accessor :source + + # Who the vendor is. + attr_accessor :vendor + + # The copyright for this project + attr_accessor :copyright + + # The RubyForge project. + attr_accessor :rfproject + + # The list of files. Only used for gem tasks. + attr_writer :filelist + + # The directory in which to store packages. Defaults to "pkg". + attr_accessor :package_dir + + # The default task. Defaults to the 'alltests' task. + attr_accessor :defaulttask + + # The defined requirements + attr_reader :requires + + # The file containing the version string. + attr_accessor :versionfile + + # Print messages on stdout + def announce(msg = nil) + puts msg + end + + # Print messages on stderr + def warn(msg = nil) + $stderr.puts msg + end + + def add_dependency(name, version) + @requires[name] = version + end + + # Where we'll be putting the code. + def codedir + unless defined? @codedir + @codedir = File.join(self.package_dir, "#{@name}-#{@version}") + end + + return @codedir + end + + # Retrieve the current version from the code. + def currentversion + unless defined? @currentversion + ver = %x{ruby -Ilib ./bin/#{@name} --version}.chomp + if $? == 0 and ver != "" + @currentversion = ver + else + warn "Could not retrieve current version; using 0.0.0" + @currentversion = "0.0.0" + end + end + + return @currentversion + end + + # Define all of our package tasks. We just search through all of our + # defined methods and call anything that's listed as making tasks. + def define + self.methods.find_all { |method| method.to_s =~ /^mktask/ }.each { |method| + self.send(method) + } + end + + def egrep(pattern) + Dir['**/*.rb'].each do |fn| + count = 0 + open(fn) do |f| + while line = f.gets + count += 1 + if line =~ pattern + puts "#{fn}:#{count}:#{line}" + end + end + end + end + end + + # List all of the files. + def filelist + unless defined? @createdfilelist + # If they passed in a file list as an array, then create a FileList + # object out of it. + if defined? @filelist + unless @filelist.is_a? FileList + @filelist = FileList[@filelist] + end + else + # Use a default file list. + @filelist = FileList[ + 'install.rb', + '[A-Z]*', + 'lib/**/*.rb', + 'test/**/*.rb', + 'bin/**/*', + 'ext/**/*', + 'examples/**/*', + 'conf/**/*' + ] + end + @filelist.delete_if {|item| item.include?(".git")} + + @createdfilelist = true + end + + @filelist + end + + def has?(feature) + feature = feature.intern if feature.is_a? String + if $features.include?(feature) + return $features[feature] + else + return true + end + end + + def initialize(name, version = nil) + @name = name + + if ENV['REL'] + @version = ENV['REL'] + else + @version = version || self.currentversion + end + + @defaulttask = :alltests + @publishdir = "/opt/rl/docroots/reductivelabs.com/htdocs/downloads" + @pkgpublishdir = "#{@publishdir}/#{@name}" + + @email = "dev@reductivelabs.com" + @url = "http://reductivelabs.com/projects/#{@name}" + @source = "http://reductivelabs.com/downloads/#{@name}/#{@name}-#{@version}.tgz" + @vendor = "Reductive Labs, LLC" + @copyright = "Copyright 2003-2008, Reductive Labs, LLC. Some Rights Reserved." + @rfproject = @name + + @defaulttask = :package + + @package_dir = "pkg" + + @requires = {} + + @versionfile = "lib/#{@name}.rb" + + CLOBBER.include('doc/*') + + yield self if block_given? + define if block_given? + end + + def mktaskhtml + if $features[:rdoc] + Rake::RDocTask.new(:html) { |rdoc| + rdoc.rdoc_dir = 'html' + rdoc.template = 'html' + rdoc.title = @name.capitalize + rdoc.options << '--line-numbers' << '--inline-source' << + '--main' << 'README' + rdoc.rdoc_files.include('README', 'COPYING', 'CHANGELOG') + rdoc.rdoc_files.include('lib/**/*.rb') + CLEAN.include("html") + } + + # Publish the html. + task :publish => [:package, :html] do + puts Dir.getwd + sh %{cp -r html #{self.pkgpublishdir}/apidocs} + end + else + warn "No rdoc; skipping html" + end + end + + # Create a release task. + def mktaskrelease + desc "Make a new release" + task :release => [ + :prerelease, + :clobber, + :update_version, + :commit_newversion, + :trac_version, + :tag, # tag everything before we make a bunch of extra dirs + :html, + :package, + :publish + ] do + + announce + announce "**************************************************************" + announce "* Release #{@version} Complete." + announce "* Packages ready to upload." + announce "**************************************************************" + announce + end + end + + # Do any prerelease work. + def mktaskprerelease + # Validate that everything is ready to go for a release. + task :prerelease do + announce + announce "**************************************************************" + announce "* Making Release #{@version}" + announce "* (current version #{self.currentversion})" + announce "**************************************************************" + announce + + # Is a release number supplied? + unless ENV['REL'] + warn "You must provide a release number when releasing" + fail "Usage: rake release REL=x.y.z [REUSE=tag_suffix]" + end + + # Is the release different than the current release. + # (or is REUSE set?) + if @version == self.currentversion && ! ENV['REUSE'] + fail "Current version is #{@version}, must specify REUSE=tag_suffix to reuse version" + end + + # Are all source files checked in? + if ENV['RELTEST'] + announce "Release Task Testing, skipping checked-in file test" + else + announce "Checking for unchecked-in files..." + data = %x{git status} + unless data.include?("nothing to commit") + fail "git status is not clean ... do you have unchecked-in files?" + end + announce "No outstanding checkins found ... OK" + end + end + end + + # Create the task to update versions. + def mktaskupdateversion + task :update_version => [:prerelease] do + if @version == self.currentversion + announce "No version change ... skipping version update" + else + announce "Updating #{@versionfile} version to #{@version}" + open(@versionfile) do |rakein| + open("#{@versionfile}.new", "w") do |rakeout| + rakein.each do |line| + if line =~ /^(\s*)#{@name.upcase}VERSION\s*=\s*/ + rakeout.puts "#{$1}#{@name.upcase}VERSION = '#{@version}'" + else + rakeout.puts line + end + end + end + end + mv "#{@versionfile}.new", @versionfile + + end + end + + desc "Commit the new versions to SVN." + task :commit_newversion => [:update_version] do + if ENV['RELTEST'] + announce "Release Task Testing, skipping commiting of new version" + else + sh %{git commit -m "Updated to version #{@version}" #{@versionfile}} + end + end + end + + def mktasktrac_version + task :trac_version => [:update_version] do + tracpath = "/opt/rl/trac/#{@name}" + + unless FileTest.exists?(tracpath) + announce "No Trac instance at %s" % tracpath + else + output = %x{sudo trac-admin #{tracpath} version list}.chomp.split("\n") + versions = {} + output[3..-1].each do |line| + name, time = line.chomp.split(/\s+/) + versions[name] = time + end + + if versions.include?(@version) + announce "Version #{@version} already in Trac" + else + announce "Adding #{@name} version #{@version} to Trac" + date = [Time.now.year.to_s, + Time.now.month.to_s, + Time.now.day.to_s].join("-") + system("sudo trac-admin #{tracpath} version add #{@version} #{date}") + end + end + end + end + + # Create the tag task. + def mktasktag + desc "Tag all the files with the latest release number (REL=x.y.z)" + task :tag => [:prerelease] do + reltag = @version + announce "Tagging with [#{reltag}]" + + if ENV['RELTEST'] + announce "Release Task Testing, skipping tagging" + else + sh %{git tag #{reltag}} + end + end + end + + # Create the task for testing across all hosts. + def mktaskhosttest + desc "Test Puppet on each test host" + task :hosttest do + out = "" + TESTHOSTS.each { |host| + puts "testing %s" % host + cwd = Dir.getwd + file = "/tmp/#{@name}-#{host}test.out" + system("ssh #{host} 'cd git/#{@name}/test; sudo rake' 2>&1 >#{file}") + + if $? != 0 + puts "%s failed; output is in %s" % [host, file] + end + } + end + end + + def mktaskri + # Create a task to build the RDOC documentation tree. + + #Rake::RDocTask.new("ri") { |rdoc| + # #rdoc.rdoc_dir = 'html' + # #rdoc.template = 'html' + # rdoc.title = "Puppet" + # rdoc.options << '--ri' << '--line-numbers' << '--inline-source' << '--main' << 'README' + # rdoc.rdoc_files.include('README', 'COPYING', 'CHANGELOG') + # rdoc.rdoc_files.include('lib/**/*.rb', 'doc/**/*.rdoc') + #} + + if $features[:rdoc] + task :ri do |ri| + files = ['README', 'COPYING', 'CHANGELOG'] + Dir.glob('lib/**/*.rb') + puts "files are \n%s" % files.join("\n") + begin + ri = RDoc::RDoc.new + ri.document(["--ri-site"] + files) + rescue RDoc::RDocError => detail + puts "Failed to build docs: %s" % detail + return nil + rescue LoadError + puts "Missing rdoc; cannot build documentation" + return nil + end + end + else + warn "No rdoc; skipping ri." + end + end + + desc "Install the application using the standard install.rb script" + task :install do + ruby "install.rb" + end + + def mktaskdefault + if dtask = self.defaulttask + desc "Default task" + task :default => dtask + end + end + + desc "Run all unit tests." + task :alltests do + if FileTest.exists?("test/Rakefile") + sh %{cd test; rake} + else + Dir.chdir("test") do + Dir.entries(".").find_all { |f| f =~ /\.rb/ }.each do |f| + sh %{ruby #{f}} + end + end + end + end + + desc "List all ruby files" + task :rubyfiles do + puts Dir['**/*.rb'].reject { |fn| fn =~ /^pkg/ } + puts Dir['**/bin/*'].reject { |fn| fn =~ /svn|(~$)|(\.rb$)/ } + end + + desc "Look for TODO and FIXME tags in the code" + task :todo do + egrep "/#.*(FIXME|TODO|TBD)/" + end + + # This task requires extra information from the Rake file. + def mkgemtask + # ==================================================================== + # Create a task that will package the Rake software into distributable + # tar, zip and gem files. + if ! defined?(Gem) + puts "Package Target requires RubyGEMs" + else + spec = Gem::Specification.new { |s| + + #### Basic information. + + s.name = self.name + s.version = self.version + s.summary = self.summary + s.description = self.description + s.platform = Gem::Platform::RUBY + + #### Dependencies and requirements. + + # I'd love to explicitly list all of the libraries that I need, + # but gems seem to only be able to handle dependencies on other + # gems, which is, um, stupid. + self.requires.each do |name, version| + s.add_dependency(name, ">= #{version}") + end + + s.files = filelist.to_a + + #### Signing key and cert chain + #s.signing_key = '/..../gem-private_key.pem' + #s.cert_chain = ['gem-public_cert.pem'] + + #### Author and project details. + + s.author = [self.author] + s.email = self.email + s.homepage = self.url + s.rubyforge_project = self.rfproject + + yield s + } + + Rake::GemPackageTask.new(spec) { |pkg| + pkg.need_tar = true + } + + desc "Copy the newly created package into the downloads directory" + task :publish => [:package] do + puts Dir.getwd + sh %{cp pkg/#{@name}-#{@version}.gem #{self.publishdir}/gems} + sh %{gem generate_index -d #{self.publishdir}} + sh %{cp pkg/#{@name}-#{@version}.tgz #{self.pkgpublishdir}} + sh %{ln -sf #{@name}-#{@version}.tgz #{self.pkgpublishdir}/#{@name}-latest.tgz} + end + CLEAN.include("pkg") + end + end +end |