summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2009-02-13 18:24:34 -0600
committerLuke Kanies <luke@madstop.com>2009-02-13 18:24:34 -0600
commit3fbec120768d84d208b14f574dfe916e25cfdbef (patch)
tree865d59f4ea9cf3782db46ce1ae7fd54b95945035
parenta2270b4a4f093c6c4f171dcf0c0e05fe101dd979 (diff)
parent2561c8e252dcf66890513458750bb1329a03beec (diff)
downloadpuppet-3fbec120768d84d208b14f574dfe916e25cfdbef.tar.gz
puppet-3fbec120768d84d208b14f574dfe916e25cfdbef.tar.xz
puppet-3fbec120768d84d208b14f574dfe916e25cfdbef.zip
Merge branch '0.24.x'
Conflicts: lib/puppet/indirector/facts/facter.rb lib/puppet/provider/augeas/augeas.rb lib/puppet/util/filetype.rb spec/unit/indirector/facts/facter.rb spec/unit/provider/augeas/augeas.rb test/util/filetype.rb
-rw-r--r--CHANGELOG16
-rw-r--r--ext/vim/syntax/puppet.vim2
-rwxr-xr-xlib/puppet/external/nagios/base.rb25
-rw-r--r--lib/puppet/indirector/facts/facter.rb8
-rw-r--r--lib/puppet/network/xmlrpc/client.rb166
-rw-r--r--lib/puppet/parser/functions/regsubst.rb93
-rw-r--r--lib/puppet/parser/functions/sprintf.rb17
-rw-r--r--lib/puppet/provider/augeas/augeas.rb36
-rw-r--r--lib/puppet/provider/naginator.rb5
-rw-r--r--lib/puppet/provider/package/up2date.rb6
-rwxr-xr-xlib/puppet/provider/parsedfile.rb14
-rwxr-xr-xlib/puppet/provider/service/redhat.rb2
-rw-r--r--lib/puppet/rails/database/003_add_environment_to_host.rb8
-rw-r--r--lib/puppet/type/augeas.rb8
-rw-r--r--lib/puppet/util/autoload.rb4
-rwxr-xr-xlib/puppet/util/filetype.rb98
-rwxr-xr-xspec/unit/indirector/facts/facter.rb38
-rwxr-xr-xspec/unit/network/xmlrpc/client.rb172
-rw-r--r--spec/unit/parser/functions/regsubst.rb88
-rw-r--r--spec/unit/parser/functions/sprintf.rb42
-rw-r--r--spec/unit/provider/augeas/augeas.rb30
-rwxr-xr-xspec/unit/provider/parsedfile.rb36
-rwxr-xr-xspec/unit/util/autoload.rb39
-rw-r--r--spec/unit/util/filetype.rb110
-rwxr-xr-xtest/util/filetype.rb137
25 files changed, 856 insertions, 344 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a878c3035..df1f8ecf7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,6 +14,22 @@
Fixed #1840 - Bug fixes and improvements for Emacs puppet-mode.el
0.24.8
+ Fixed #1831 - Added sprintf function
+
+ Fixed #1830 - Added regsubst function
+
+ Updated up2date and service confines to add support for Oracle EL and VM
+
+ Fixing #1948 and #1953 - augeas ins bug: wrong number of arguments (1 for 3)
+
+ Fixing #944 - changing error message from warning to info - connection recycled
+
+ Fixed #961 - puppetd creating too many/not closing TCP connections
+
+ Fixed #1959 - Added column protection for environment schema migration
+
+ Fixing #1869 - autoloaded files should never leak exceptions
+
Fixing #1543 - Nagios parse errors no longer kill Puppet
Fixed #1420 - nagios_serviceescalation not allowing host_name more than one type
diff --git a/ext/vim/syntax/puppet.vim b/ext/vim/syntax/puppet.vim
index 5a50f5ce0..e54d32aa8 100644
--- a/ext/vim/syntax/puppet.vim
+++ b/ext/vim/syntax/puppet.vim
@@ -16,7 +16,7 @@ elseif exists("b:current_syntax")
finish
endif
-syn region puppetDefine start="^\s*\(class\|define\|site\|node\)" end="{" contains=puppetDefType,puppetDefName,puppetDefArguments
+syn region puppetDefine start="^\s*\(class\|define\|node\)" end="{" contains=puppetDefType,puppetDefName,puppetDefArguments
syn keyword puppetDefType class define site node inherits contained
syn keyword puppetInherits inherits contained
syn region puppetDefArguments start="(" end=")" contains=puppetArgument
diff --git a/lib/puppet/external/nagios/base.rb b/lib/puppet/external/nagios/base.rb
index d95b808dd..6a0c1831c 100755
--- a/lib/puppet/external/nagios/base.rb
+++ b/lib/puppet/external/nagios/base.rb
@@ -416,18 +416,20 @@ class Nagios::Base
:dependent_service_description, :host_name, :hostgroup_name,
:service_description, :inherits_parent, :execution_failure_criteria,
:notification_failure_criteria, :dependency_period,
- :register, :use
+ :register, :use,
+ :_naginator_name
- setnamevar :service_description
+ setnamevar :_naginator_name
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
+ :register, :use,
+ :_naginator_name
- setnamevar :service_description
+ setnamevar :_naginator_name
end
newtype :hostdependency do
@@ -435,18 +437,20 @@ 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
+ :register, :use,
+ :_naginator_name
- setnamevar :host_name
+ setnamevar :_naginator_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
+ :register, :use,
+ :_naginator_name
- setnamevar :host_name
+ setnamevar :_naginator_name
end
newtype :hostextinfo do
@@ -463,9 +467,10 @@ class Nagios::Base
setparameters :host_name, :service_description, :notes, :notes_url,
:action_url, :icon_image, :icon_image_alt,
- :register, :use
+ :register, :use,
+ :_naginator_name
- setnamevar :service_description
+ setnamevar :_naginator_name
end
end
diff --git a/lib/puppet/indirector/facts/facter.rb b/lib/puppet/indirector/facts/facter.rb
index 6376b71ca..e664e17c7 100644
--- a/lib/puppet/indirector/facts/facter.rb
+++ b/lib/puppet/indirector/facts/facter.rb
@@ -8,8 +8,12 @@ class Puppet::Node::Facts::Facter < Puppet::Indirector::Code
def self.load_fact_plugins
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = Puppet[:factpath].split(":").each do |dir|
+ # Add any per-module fact directories to the factpath
+ module_fact_dirs = Puppet[:modulepath].split(":").collect do |d|
+ Dir.glob("%s/*/plugins/facter" % d)
+ end.flatten
+ dirs = module_fact_dirs + Puppet[:factpath].split(":")
+ x = dirs.each do |dir|
load_facts_in_dir(dir)
end
end
diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb
index 37ace2101..678ab6c00 100644
--- a/lib/puppet/network/xmlrpc/client.rb
+++ b/lib/puppet/network/xmlrpc/client.rb
@@ -36,57 +36,7 @@ module Puppet::Network
interface.methods.each { |ary|
method = ary[0]
newclient.send(:define_method,method) { |*args|
- Puppet.debug "Calling %s.%s" % [namespace, method]
- begin
- call("%s.%s" % [namespace, method.to_s],*args)
- rescue OpenSSL::SSL::SSLError => detail
- if detail.message =~ /bad write retry/
- Puppet.warning "Transient SSL write error; restarting connection and retrying"
- self.recycle_connection
- retry
- end
- ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
- if detail.message.include?(str)
- Puppet.warning "Certificate validation failed; consider using the certname configuration option"
- end
- end
- raise XMLRPCClientError,
- "Certificates were not trusted: %s" % detail
- rescue ::XMLRPC::FaultException => detail
- raise XMLRPCClientError, detail.faultString
- rescue Errno::ECONNREFUSED => detail
- msg = "Could not connect to %s on port %s" %
- [@host, @port]
- raise XMLRPCClientError, msg
- rescue SocketError => detail
- Puppet.err "Could not find server %s: %s" %
- [@host, detail.to_s]
- error = XMLRPCClientError.new(
- "Could not find server %s" % @host
- )
- error.set_backtrace detail.backtrace
- raise error
- rescue Errno::EPIPE, EOFError
- Puppet.warning "Other end went away; restarting connection and retrying"
- self.recycle_connection
- retry
- rescue Timeout::Error => detail
- Puppet.err "Connection timeout calling %s.%s: %s" %
- [namespace, method, detail.to_s]
- error = XMLRPCClientError.new("Connection Timeout")
- error.set_backtrace(detail.backtrace)
- raise error
- rescue => detail
- if detail.message =~ /^Wrong size\. Was \d+, should be \d+$/
- Puppet.warning "XMLRPC returned wrong size. Retrying."
- retry
- end
- Puppet.err "Could not call %s.%s: %s" %
- [namespace, method, detail.inspect]
- error = XMLRPCClientError.new(detail.to_s)
- error.set_backtrace detail.backtrace
- raise error
- end
+ make_rpc_call(namespace, method, *args)
}
}
@@ -97,13 +47,119 @@ module Puppet::Network
@clients[handler] || self.mkclient(handler)
end
+ class ErrorHandler
+ def initialize(&block)
+ metaclass.define_method(:execute, &block)
+ end
+ end
+
+ # Use a class variable so all subclasses have access to it.
+ @@error_handlers = {}
+
+ def self.error_handler(exception)
+ if handler = @@error_handlers[exception.class]
+ return handler
+ else
+ return @@error_handlers[:default]
+ end
+ end
+
+ def self.handle_error(*exceptions, &block)
+ handler = ErrorHandler.new(&block)
+
+ exceptions.each do |exception|
+ @@error_handlers[exception] = handler
+ end
+ end
+
+ handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
+ if detail.message =~ /bad write retry/
+ Puppet.warning "Transient SSL write error; restarting connection and retrying"
+ client.recycle_connection
+ return :retry
+ end
+ ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
+ if detail.message.include?(str)
+ Puppet.warning "Certificate validation failed; consider using the certname configuration option"
+ end
+ end
+ raise XMLRPCClientError, "Certificates were not trusted: %s" % detail
+ end
+
+ handle_error(:default) do |client, detail, namespace, method|
+ if detail.message.to_s =~ /^Wrong size\. Was \d+, should be \d+$/
+ Puppet.warning "XMLRPC returned wrong size. Retrying."
+ return :retry
+ end
+ Puppet.err "Could not call %s.%s: %s" % [namespace, method, detail.inspect]
+ error = XMLRPCClientError.new(detail.to_s)
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+
+ handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
+ if detail.message =~ /bad write retry/
+ Puppet.warning "Transient SSL write error; restarting connection and retrying"
+ client.recycle_connection
+ return :retry
+ end
+ ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
+ if detail.message.include?(str)
+ Puppet.warning "Certificate validation failed; consider using the certname configuration option"
+ end
+ end
+ raise XMLRPCClientError, "Certificates were not trusted: %s" % detail
+ end
+
+ handle_error(::XMLRPC::FaultException) do |client, detail, namespace, method|
+ raise XMLRPCClientError, detail.faultString
+ end
+
+ handle_error(Errno::ECONNREFUSED) do |client, detail, namespace, method|
+ msg = "Could not connect to %s on port %s" % [client.host, client.port]
+ raise XMLRPCClientError, msg
+ end
+
+ handle_error(SocketError) do |client, detail, namespace, method|
+ Puppet.err "Could not find server %s: %s" % [@host, detail.to_s]
+ error = XMLRPCClientError.new("Could not find server %s" % client.host)
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+
+ handle_error(Errno::EPIPE, EOFError) do |client, detail, namespace, method|
+ Puppet.info "Other end went away; restarting connection and retrying"
+ client.recycle_connection
+ return :retry
+ end
+
+ handle_error(Timeout::Error) do |client, detail, namespace, method|
+ Puppet.err "Connection timeout calling %s.%s: %s" % [namespace, method, detail.to_s]
+ error = XMLRPCClientError.new("Connection Timeout")
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
+
+ def make_rpc_call(namespace, method, *args)
+ Puppet.debug "Calling %s.%s" % [namespace, method]
+ begin
+ call("%s.%s" % [namespace, method.to_s],*args)
+ rescue Exception => detail
+ retry if self.class.error_handler(detail).execute(self, detail, namespace, method) == :retry
+ end
+ ensure
+ http.finish if http.started?
+ end
+
def http
unless @http
- @http = Puppet::Network::HttpPool.http_instance(@host, @port, true)
+ @http = Puppet::Network::HttpPool.http_instance(host, port, true)
end
@http
end
+ attr_reader :host, :port
+
def initialize(hash = {})
hash[:Path] ||= "/RPC2"
hash[:Server] ||= Puppet[:server]
@@ -135,7 +191,11 @@ module Puppet::Network
# or we've just downloaded certs and we need to create new http instances
# with the certs added.
def recycle_connection
- @http = Puppet::Network::HttpPool.http_instance(@host, @port, true) # reset the instance
+ if http.started?
+ http.finish
+ end
+ @http = nil
+ self.http # force a new one
end
def start
diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb
new file mode 100644
index 000000000..067d75c51
--- /dev/null
+++ b/lib/puppet/parser/functions/regsubst.rb
@@ -0,0 +1,93 @@
+module Puppet::Parser::Functions
+ newfunction(:regsubst, :type => :rvalue,
+ :doc => "\
+ Perform regexp replacement on a string.
+
+ Parameters (in order):
+
+ :str:
+ The string to operate on.
+
+ :regexp:
+ The regular expression matching the string. If you want it
+ anchored at the start and/or end of the string, you must do
+ that with ^ and $ yourself.
+
+ :replacement:
+ Replacement string. Can contain back references to what was
+ matched using \\0, \\1, and so on.
+
+ :flags:
+ Optional. String of single letter flags for how the regexp
+ is interpreted:
+
+ - **E**
+ Extended regexps
+ - **I**
+ Ignore case in regexps
+ - **M**
+ Multiline regexps
+ - **G**
+ Global replacement; all occurances of the regexp in
+ the string will be replaced. Without this, only the
+ first occurance will be replaced.
+
+ :lang:
+ Optional. How to handle multibyte characters. A
+ single-character string with the following values:
+
+ - **N**
+ None
+ - **E**
+ EUC
+ - **S**
+ SJIS
+ - **U**
+ UTF-8
+
+ **Examples**
+
+ Get the third octet from the node's IP address: ::
+
+ $i3 = regsubst($ipaddress,
+ '^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$',
+ '\\\\3')
+
+ Put angle brackets around each octet in the node's IP address: ::
+
+ $x = regsubst($ipaddress, '([0-9]+)', '<\\\\1>', 'G')
+ ") \
+ do |args|
+ flag_mapping = {
+ "E" => Regexp::EXTENDED,
+ "I" => Regexp::IGNORECASE,
+ "M" => Regexp::MULTILINE,
+ }
+ if args.length < 3 or args.length > 5
+ raise Puppet::ParseError, ("regsub(): wrong number of arguments" +
+ " (#{args.length}; min 3, max 5)")
+ end
+ str, regexp, replacement, flags, lang = args
+ reflags = 0
+ global = false
+ (flags or "").each_byte do |f|
+ f = f.chr
+ if f == "G"
+ global = true
+ else
+ fvalue = flag_mapping[f]
+ if !fvalue
+ raise Puppet::ParseError, "regsub(): bad flag `#{f}'"
+ end
+ reflags |= fvalue
+ end
+ end
+ re = Regexp.compile(regexp, reflags, lang)
+ if global
+ result = str.gsub(re, replacement)
+ else
+ result = str.sub(re, replacement)
+ end
+ return result
+ end
+end
diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb
new file mode 100644
index 000000000..79744104d
--- /dev/null
+++ b/lib/puppet/parser/functions/sprintf.rb
@@ -0,0 +1,17 @@
+module Puppet::Parser::Functions
+ newfunction(:sprintf, :type => :rvalue,
+ :doc => "\
+ Perform printf-style formatting of text.
+
+ The first parameter is format string describing how the rest of the
+ parameters should be formatted. See the documentation for the
+ ``Kernel::sprintf()`` function in Ruby for all the details.
+ ") \
+ do |args|
+ if args.length < 1
+ raise Puppet::ParseError, 'sprintf() needs at least one argument'
+ end
+ fmt = args.shift()
+ return sprintf(fmt, *args)
+ end
+end
diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb
index 919b377e7..2457840d1 100644
--- a/lib/puppet/provider/augeas/augeas.rb
+++ b/lib/puppet/provider/augeas/augeas.rb
@@ -69,7 +69,6 @@ Puppet::Type.type(:augeas).provide(:augeas) do
commands.concat(parse_commands(datum))
end
end
-
return commands
end
@@ -181,15 +180,36 @@ Puppet::Type.type(:augeas).provide(:augeas) do
fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2
command = cmd_array[0]
cmd_array.shift()
- loc = cmd_array[0]
- cmd_array[0]=File.join(context, loc)
- debug("sending command '#{command}' with params #{cmd_array.inspect}")
begin
case command
- when "set": aug.set(cmd_array[0], cmd_array[1])
- when "rm", "remove": aug.rm(cmd_array[0])
- when "clear": aug.clear(cmd_array[0])
- when "insert", "ins": aug.insert(cmd_array[0])
+ when "set":
+ cmd_array[0]=File.join(context, cmd_array[0])
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ aug.set(cmd_array[0], cmd_array[1])
+ when "rm", "remove":
+ cmd_array[0]=File.join(context, cmd_array[0])
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ aug.rm(cmd_array[0])
+ when "clear":
+ cmd_array[0]=File.join(context, cmd_array[0])
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ aug.clear(cmd_array[0])
+ when "insert", "ins"
+
+ ext_array = cmd_array[1].split(" ") ;
+ if cmd_array.size < 2 or ext_array.size < 2
+ fail("ins requires 3 parameters")
+ end
+ label = cmd_array[0]
+ where = ext_array[0]
+ path = File.join(context, ext_array[1])
+ case where
+ when "before": before = true
+ when "after": before = false
+ else fail("Invalid value '#{where}' for where param")
+ end
+ debug("sending command '#{command}' with params #{[label, where, path].inspect()}")
+ aug.insert(path, label, before)
else fail("Command '#{command}' is not supported")
end
rescue Exception => e
diff --git a/lib/puppet/provider/naginator.rb b/lib/puppet/provider/naginator.rb
index 233d82eb6..5510eb9c8 100644
--- a/lib/puppet/provider/naginator.rb
+++ b/lib/puppet/provider/naginator.rb
@@ -7,6 +7,7 @@ require 'puppet/external/nagios'
# The base class for all Naginator providers.
class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile
+ NAME_STRING = "## --PUPPET_NAME-- (called '_naginator_name' in the manifest)"
# Retrieve the associated class from Nagios::Base.
def self.nagios_type
unless defined?(@nagios_type) and @nagios_type
@@ -24,14 +25,14 @@ class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile
def self.parse(text)
begin
- Nagios::Parser.new.parse(text)
+ Nagios::Parser.new.parse(text.gsub(NAME_STRING, "_naginator_name"))
rescue => detail
raise Puppet::Error, "Could not parse configuration for %s: %s" % [resource_type.name, detail]
end
end
def self.to_file(records)
- header + records.collect { |record| record.to_s }.join("\n")
+ header + records.collect { |record| record.to_s }.join("\n").gsub("_naginator_name", NAME_STRING)
end
def self.skip_record?(record)
diff --git a/lib/puppet/provider/package/up2date.rb b/lib/puppet/provider/package/up2date.rb
index aa7c9eaf0..5708905cc 100644
--- a/lib/puppet/provider/package/up2date.rb
+++ b/lib/puppet/provider/package/up2date.rb
@@ -3,9 +3,11 @@ Puppet::Type.type(:package).provide :up2date, :parent => :rpm, :source => :rpm d
mechanism."
commands :up2date => "/usr/sbin/up2date-nox"
- defaultfor :operatingsystem => :redhat,
+
+ defaultfor :operatingsystem => [:redhat, :oel, :ovm]
:lsbdistrelease => ["2.1", "3", "4"]
- confine :operatingsystem => :redhat
+
+ confine :operatingsystem => [:redhat, :oel, :ovm]
# Install a package using 'up2date'.
def install
diff --git a/lib/puppet/provider/parsedfile.rb b/lib/puppet/provider/parsedfile.rb
index a4c4bc87c..45eae57ff 100755
--- a/lib/puppet/provider/parsedfile.rb
+++ b/lib/puppet/provider/parsedfile.rb
@@ -78,8 +78,22 @@ class Puppet::Provider::ParsedFile < Puppet::Provider
@modified.reject! { |t| flushed.include?(t) }
end
+ # Make sure our file is backed up, but only back it up once per transaction.
+ # We cheat and rely on the fact that @records is created on each prefetch.
+ def self.backup_target(target)
+ unless defined?(@backup_stats)
+ @backup_stats = {}
+ end
+ return nil if @backup_stats[target] == @records.object_id
+
+ target_object(target).backup
+ @backup_stats[target] = @records.object_id
+ end
+
# Flush all of the records relating to a specific target.
def self.flush_target(target)
+ backup_target(target)
+
records = target_records(target).reject { |r|
r[:ensure] == :absent
}
diff --git a/lib/puppet/provider/service/redhat.rb b/lib/puppet/provider/service/redhat.rb
index c6c3540f5..031db46c1 100755
--- a/lib/puppet/provider/service/redhat.rb
+++ b/lib/puppet/provider/service/redhat.rb
@@ -9,7 +9,7 @@ Puppet::Type.type(:service).provide :redhat, :parent => :init do
commands :chkconfig => "/sbin/chkconfig", :service => "/sbin/service"
- defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles]
+ defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles, :oel, :ovm]
def self.defpath
superclass.defpath
diff --git a/lib/puppet/rails/database/003_add_environment_to_host.rb b/lib/puppet/rails/database/003_add_environment_to_host.rb
index 4593a06f7..3ed10e946 100644
--- a/lib/puppet/rails/database/003_add_environment_to_host.rb
+++ b/lib/puppet/rails/database/003_add_environment_to_host.rb
@@ -1,9 +1,13 @@
class AddEnvironmentToHost < ActiveRecord::Migration
def self.up
- add_column :hosts, :environment, :string
+ unless ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
+ add_column :hosts, :environment, :string
+ end
end
def self.down
- remove_column :hosts, :environment
+ if ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
+ remove_column :hosts, :environment
+ end
end
end
diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb
index 67b62e886..c89400b5e 100644
--- a/lib/puppet/type/augeas.rb
+++ b/lib/puppet/type/augeas.rb
@@ -92,10 +92,12 @@ Puppet::Type.newtype(:augeas) do
rm [PATH] Removes the node at location PATH
remove [PATH] Synonym for rm
clear [PATH] Keeps the node at PATH, but removes the value.
- ins [PATH] Inserts an empty node at PATH.
- insert [PATH] Synonym for ins
+ ins [LABEL] [WHERE] [PATH]
+ Inserts an empty node LABEL either [WHERE={before|after}] PATH.
+ insert [LABEL] [WHERE] [PATH]
+ Synonym for ins
- If the parameter 'context' is set that that value is prepended to PATH"
+ If the parameter 'context' is set that value is prepended to PATH"
munge do |value|
provider.parse_commands(value)
diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb
index 535d9ef2e..0c80f8b06 100644
--- a/lib/puppet/util/autoload.rb
+++ b/lib/puppet/util/autoload.rb
@@ -78,7 +78,7 @@ class Puppet::Util::Autoload
name = symbolize(name)
loaded name, file
return true
- rescue LoadError => detail
+ rescue Exception => detail
# I have no idea what's going on here, but different versions
# of ruby are raising different errors on missing files.
unless detail.to_s =~ /^no such file/i
@@ -115,7 +115,7 @@ class Puppet::Util::Autoload
begin
Kernel.require file
loaded(name, file)
- rescue => detail
+ rescue Exception => detail
if Puppet[:trace]
puts detail.backtrace
end
diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb
index a58b9a23b..0f184d5c2 100755
--- a/lib/puppet/util/filetype.rb
+++ b/lib/puppet/util/filetype.rb
@@ -74,7 +74,7 @@ class Puppet::Util::FileType
# Back the file up before replacing it.
def backup
- bucket.backup(@path) if FileTest.exists?(@path)
+ bucket.backup(@path) if File.exists?(@path)
end
# Pick or create a filebucket to use.
@@ -94,7 +94,7 @@ class Puppet::Util::FileType
newfiletype(:flat) do
# Read the file.
def read
- if File.exists?(@path)
+ if File.exist?(@path)
File.read(@path)
else
return nil
@@ -103,17 +103,13 @@ class Puppet::Util::FileType
# Remove the file.
def remove
- if File.exists?(@path)
+ if File.exist?(@path)
File.unlink(@path)
end
end
# Overwrite the file.
def write(text)
- backup()
-
- raise("Cannot create file %s in absent directory" % @path) unless FileTest.exist?(File.dirname(@path))
-
require "tempfile"
tf = Tempfile.new("puppet")
tf.print text; tf.flush
@@ -255,92 +251,4 @@ class Puppet::Util::FileType
output_file.delete
end
end
-
- # Treat netinfo tables as a single file, just for simplicity of certain
- # types
- newfiletype(:netinfo) do
- class << self
- attr_accessor :format
- end
- def read
- %x{nidump -r /#{@path} /}
- end
-
- # This really only makes sense for cron tabs.
- def remove
- %x{nireport / /#{@path} name}.split("\n").each do |name|
- newname = name.gsub(/\//, '\/').sub(/\s+$/, '')
- output = %x{niutil -destroy / '/#{@path}/#{newname}'}
-
- unless $? == 0
- raise Puppet::Error, "Could not remove %s from %s" %
- [name, @path]
- end
- end
- end
-
- # Convert our table to an array of hashes. This only works for
- # handling one table at a time.
- def to_array(text = nil)
- unless text
- text = read
- end
-
- hash = nil
-
- # Initialize it with the first record
- records = []
- text.split("\n").each do |line|
- next if line =~ /^[{}]$/ # Skip the wrapping lines
- next if line =~ /"name" = \( "#{@path}" \)/ # Skip the table name
- next if line =~ /CHILDREN = \(/ # Skip this header
- next if line =~ /^ \)/ # and its closer
-
- # Now we should have nothing but records, wrapped in braces
-
- case line
- when /^\s+\{/: hash = {}
- when /^\s+\}/: records << hash
- when /\s+"(\w+)" = \( (.+) \)/
- field = $1
- values = $2
-
- # Always use an array
- hash[field] = []
-
- values.split(/, /).each do |value|
- if value =~ /^"(.*)"$/
- hash[field] << $1
- else
- raise ArgumentError, "Could not match value %s" % value
- end
- end
- else
- raise ArgumentError, "Could not match line %s" % line
- end
- end
-
- records
- end
-
- def write(text)
- text.gsub!(/^#.*\n/,'')
- text.gsub!(/^$/,'')
- if text == "" or text == "\n"
- self.remove
- return
- end
- unless format = self.class.format
- raise Puppe::DevError, "You must define the NetInfo format to inport"
- end
- IO.popen("niload -d #{format} . 1>/dev/null 2>/dev/null", "w") { |p|
- p.print text
- }
-
- unless $? == 0
- raise ArgumentError, "Failed to write %s" % @path
- end
- end
- end
end
-
diff --git a/spec/unit/indirector/facts/facter.rb b/spec/unit/indirector/facts/facter.rb
index c0b9dce36..ea68f63d6 100755
--- a/spec/unit/indirector/facts/facter.rb
+++ b/spec/unit/indirector/facts/facter.rb
@@ -93,15 +93,6 @@ describe Puppet::Node::Facts::Facter do
end
end
- it "should load each directory in the Fact path when loading fact plugins" do
- Puppet.settings.expects(:value).with(:factpath).returns("one%stwo" % File::PATH_SEPARATOR)
-
- Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("one")
- Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("two")
-
- Puppet::Node::Facts::Facter.load_fact_plugins
- end
-
it "should skip files when asked to load a directory" do
FileTest.expects(:directory?).with("myfile").returns false
@@ -119,4 +110,33 @@ describe Puppet::Node::Facts::Facter do
Puppet::Node::Facts::Facter.load_facts_in_dir("mydir")
end
+
+ describe Puppet::Node::Facts::Facter, "when loading fact plugins from disk" do
+ it "should load each directory in the Fact path" do
+ Puppet.settings.stubs(:value).returns "foo"
+ Puppet.settings.expects(:value).with(:factpath).returns("one%stwo" % File::PATH_SEPARATOR)
+
+ Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("one")
+ Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("two")
+
+ Puppet::Node::Facts::Facter.load_fact_plugins
+ end
+
+ it "should load all facts from the modules" do
+ Puppet.settings.stubs(:value).returns "foo"
+ Puppet::Node::Facts::Facter.stubs(:load_facts_in_dir)
+
+ Puppet.settings.expects(:value).with(:modulepath).returns("one%stwo" % File::PATH_SEPARATOR)
+
+ Dir.expects(:glob).with("one/*/plugins/facter").returns %w{oneA oneB}
+ Dir.expects(:glob).with("two/*/plugins/facter").returns %w{twoA twoB}
+
+ Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("oneA")
+ Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("oneB")
+ Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("twoA")
+ Puppet::Node::Facts::Facter.expects(:load_facts_in_dir).with("twoB")
+
+ Puppet::Node::Facts::Facter.load_fact_plugins
+ end
+ end
end
diff --git a/spec/unit/network/xmlrpc/client.rb b/spec/unit/network/xmlrpc/client.rb
index a0a2e77fb..36e59429c 100755
--- a/spec/unit/network/xmlrpc/client.rb
+++ b/spec/unit/network/xmlrpc/client.rb
@@ -2,12 +2,170 @@
Dir.chdir(File.dirname(__FILE__)) { (s = lambda { |f| File.exist?(f) ? require(f) : Dir.chdir("..") { s.call(f) } }).call("spec/spec_helper.rb") }
-describe Puppet::Network do
- it "should raise an XMLRPCClientError if a generated class raises a Timeout::Error" do
- http = mock 'http'
- Puppet::Network::HttpPool.stubs(:http_instance).returns http
- file = Puppet::Network::Client.file.new({:Server => "foo.com"})
- http.stubs(:post2).raises Timeout::Error
- lambda { file.retrieve }.should raise_error(Puppet::Network::XMLRPCClientError)
+describe Puppet::Network::XMLRPCClient do
+ describe "when performing the rpc call" do
+ before do
+ @client = Puppet::Network::Client.report.xmlrpc_client.new
+ @client.stubs(:call).returns "foo"
+
+ end
+
+ it "should call the specified namespace and method, with the specified arguments" do
+ @client.expects(:call).with("puppetreports.report", "eh").returns "foo"
+ @client.report("eh")
+ end
+
+ it "should return the results from the call" do
+ @client.expects(:call).returns "foo"
+ @client.report("eh").should == "foo"
+ end
+
+ it "should always close the http connection if it is still open after the call" do
+ http = mock 'http'
+ @client.stubs(:http).returns http
+
+ http.expects(:started?).returns true
+ http.expects(:finish)
+
+ @client.report("eh").should == "foo"
+ end
+
+ it "should always close the http connection if it is still open after a call that raises an exception" do
+ http = mock 'http'
+ @client.stubs(:http).returns http
+
+ @client.expects(:call).raises RuntimeError
+
+ http.expects(:started?).returns true
+ http.expects(:finish)
+
+ lambda { @client.report("eh") }.should raise_error
+ end
+
+ describe "when returning the http instance" do
+ it "should use the http pool to create the instance" do
+ @client.instance_variable_set("@http", nil)
+ @client.expects(:host).returns "myhost"
+ @client.expects(:port).returns "myport"
+ Puppet::Network::HttpPool.expects(:http_instance).with("myhost", "myport", true).returns "http"
+
+ @client.http.should == "http"
+ end
+
+ it "should reuse existing instances" do
+ @client.http.should equal(@client.http)
+ end
+ end
+
+ describe "when recycling the connection" do
+ it "should close the existing instance if it's open" do
+ http = mock 'http'
+ @client.stubs(:http).returns http
+
+ http.expects(:started?).returns true
+ http.expects(:finish)
+
+ @client.recycle_connection
+ end
+
+ it "should force creation of a new instance" do
+ Puppet::Network::HttpPool.expects(:http_instance).returns "second_http"
+
+ @client.recycle_connection
+
+ @client.http.should == "second_http"
+ end
+ end
+
+ describe "and an exception is raised" do
+ it "should raise XMLRPCClientError if XMLRPC::FaultException is raised" do
+ error = XMLRPC::FaultException.new("foo", "bar")
+
+ @client.expects(:call).raises(error)
+
+ lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+
+ it "should raise XMLRPCClientError if Errno::ECONNREFUSED is raised" do
+ @client.expects(:call).raises(Errno::ECONNREFUSED)
+
+ lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+
+ it "should log and raise XMLRPCClientError if Timeout::Error is raised" do
+ Puppet.expects(:err)
+ @client.expects(:call).raises(Timeout::Error)
+
+ lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+
+ it "should log and raise XMLRPCClientError if SocketError is raised" do
+ Puppet.expects(:err)
+ @client.expects(:call).raises(SocketError)
+
+ lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+
+ it "should log, recycle the connection, and retry if Errno::EPIPE is raised" do
+ @client.expects(:call).times(2).raises(Errno::EPIPE).then.returns "eh"
+
+ Puppet.expects(:warning)
+ @client.expects(:recycle_connection)
+
+ @client.report("eh")
+ end
+
+ it "should log, recycle the connection, and retry if EOFError is raised" do
+ @client.expects(:call).times(2).raises(EOFError).then.returns "eh"
+
+ Puppet.expects(:warning)
+ @client.expects(:recycle_connection)
+
+ @client.report("eh")
+ end
+
+ it "should log and retry if an exception containing 'Wrong size' is raised" do
+ error = RuntimeError.new("Wrong size. Was 15, should be 30")
+ @client.expects(:call).times(2).raises(error).then.returns "eh"
+
+ Puppet.expects(:warning)
+
+ @client.report("eh")
+ end
+
+ it "should raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised" do
+ @client.expects(:call).raises(OpenSSL::SSL::SSLError)
+
+ lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+
+ it "should log and raise XMLRPCClientError if OpenSSL::SSL::SSLError is raised with certificate issues" do
+ error = OpenSSL::SSL::SSLError.new("hostname was not match")
+ @client.expects(:call).raises(error)
+
+ Puppet.expects(:warning)
+
+ lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+
+ it "should log, recycle the connection, and retry if OpenSSL::SSL::SSLError is raised containing 'bad write retry'" do
+ error = OpenSSL::SSL::SSLError.new("bad write retry")
+ @client.expects(:call).times(2).raises(error).then.returns "eh"
+
+ @client.expects(:recycle_connection)
+
+ Puppet.expects(:warning)
+
+ @client.report("eh")
+ end
+
+ it "should log and raise XMLRPCClientError if any other exception is raised" do
+ @client.expects(:call).raises(RuntimeError)
+
+ Puppet.expects(:err)
+
+ lambda { @client.report("eh") }.should raise_error(Puppet::Network::XMLRPCClientError)
+ end
+ end
end
end
diff --git a/spec/unit/parser/functions/regsubst.rb b/spec/unit/parser/functions/regsubst.rb
new file mode 100644
index 000000000..18f49f7d4
--- /dev/null
+++ b/spec/unit/parser/functions/regsubst.rb
@@ -0,0 +1,88 @@
+#! /usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe "the regsubst function" do
+
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ end
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("regsubst").should == "function_regsubst"
+ end
+
+ it "should raise a ParseError if there is less than 3 arguments" do
+ lambda { @scope.function_regsubst(["foo", "bar"]) }.should(
+ raise_error(Puppet::ParseError))
+ end
+
+ it "should raise a ParseError if there is more than 5 arguments" do
+ lambda { @scope.function_regsubst(["foo", "bar", "gazonk", "del", "x", "y"]) }.should(
+ raise_error(Puppet::ParseError))
+ end
+
+
+ it "should raise a ParseError when given a bad flag" do
+ lambda { @scope.function_regsubst(["foo", "bar", "gazonk", "X"]) }.should(
+ raise_error(Puppet::ParseError))
+ end
+
+ it "should handle groups" do
+ result = @scope.function_regsubst(
+ [ '130.236.254.10',
+ '^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$',
+ '\4-\3-\2-\1'
+ ])
+ result.should(eql("10-254-236-130"))
+ end
+
+ it "should handle simple regexps" do
+ result = @scope.function_regsubst(
+ [ "the monkey breaks banana trees",
+ "b[an]*a",
+ "coconut"
+ ])
+ result.should(eql("the monkey breaks coconut trees"))
+ end
+
+ it "should handle case-sensitive regexps" do
+ result = @scope.function_regsubst(
+ [ "the monkey breaks baNAna trees",
+ "b[an]+a",
+ "coconut"
+ ])
+ result.should(eql("the monkey breaks baNAna trees"))
+ end
+
+ it "should handle case-insensitive regexps" do
+ result = @scope.function_regsubst(
+ [ "the monkey breaks baNAna trees",
+ "b[an]+a",
+ "coconut",
+ "I"
+ ])
+ result.should(eql("the monkey breaks coconut trees"))
+ end
+
+ it "should handle global substitutions" do
+ result = @scope.function_regsubst(
+ [ "the monkey breaks\tbanana trees",
+ "[ \t]",
+ "--",
+ "G"
+ ])
+ result.should(eql("the--monkey--breaks--banana--trees"))
+ end
+
+ it "should handle global substitutions with groups" do
+ result = @scope.function_regsubst(
+ [ '130.236.254.10',
+ '([0-9]+)',
+ '<\1>',
+ 'G'
+ ])
+ result.should(eql('<130>.<236>.<254>.<10>'))
+ end
+
+end
diff --git a/spec/unit/parser/functions/sprintf.rb b/spec/unit/parser/functions/sprintf.rb
new file mode 100644
index 000000000..8654b18fc
--- /dev/null
+++ b/spec/unit/parser/functions/sprintf.rb
@@ -0,0 +1,42 @@
+#! /usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../spec_helper'
+
+describe "the sprintf function" do
+
+ before :each do
+ @scope = Puppet::Parser::Scope.new()
+ end
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("sprintf").should == "function_sprintf"
+ end
+
+ it "should raise a ParseError if there is less than 1 argument" do
+ lambda { @scope.function_sprintf([]) }.should(
+ raise_error(Puppet::ParseError))
+ end
+
+ it "should format integers" do
+ result = @scope.function_sprintf(["%+05d", "23"])
+ result.should(eql("+0023"))
+ end
+
+ it "should format floats" do
+ result = @scope.function_sprintf(["%+.2f", "2.7182818284590451"])
+ result.should(eql("+2.72"))
+ end
+
+ it "should format large floats" do
+ result = @scope.function_sprintf(["%+.2e", "27182818284590451"])
+ result.should(eql("+2.72e+16"))
+ end
+
+ it "should perform more complex formatting" do
+ result = @scope.function_sprintf(
+ [ "<%.8s:%#5o %#8X (%-8s)>",
+ "overlongstring", "23", "48879", "foo" ])
+ result.should(eql("<overlong: 027 0XBEEF (foo )>"))
+ end
+
+end
diff --git a/spec/unit/provider/augeas/augeas.rb b/spec/unit/provider/augeas/augeas.rb
index 083448b4a..affc66676 100644
--- a/spec/unit/provider/augeas/augeas.rb
+++ b/spec/unit/provider/augeas/augeas.rb
@@ -285,32 +285,42 @@ describe provider_class do
@augeas.expects(:clear).with("/foo/Jar/Jar")
@augeas.expects(:save).returns(true)
@provider.execute_changes.should == :executed
- end
+ end
+
- it "should handle insert commands" do
- command = [["insert", "/Jar/Jar"]]
+ it "should handle ins commands with before" do
+ command = [["ins", "Binks", "before /Jar/Jar"]]
context = "/foo"
@resource.expects(:[]).times(2).returns(command).then.returns(context)
- @augeas.expects(:insert).with("/foo/Jar/Jar")
+ @augeas.expects(:insert).with("/foo/Jar/Jar", "Binks", true)
@augeas.expects(:save).returns(true)
@provider.execute_changes.should == :executed
end
- it "should handle ins commands" do
- command = [["ins", "/Jar/Jar"]]
+ it "should handle ins commands with before" do
+ command = [["ins", "Binks", "after /Jar/Jar"]]
context = "/foo"
@resource.expects(:[]).times(2).returns(command).then.returns(context)
- @augeas.expects(:insert).with("/foo/Jar/Jar")
+ @augeas.expects(:insert).with("/foo/Jar/Jar", "Binks", false)
@augeas.expects(:save).returns(true)
@provider.execute_changes.should == :executed
end
+ it "should handle ins with no context" do
+ command = [["ins", "Binks", "after /Jar/Jar"]]
+ context = "" # this is the default
+ @resource.expects(:[]).times(2).returns(command).then.returns(context)
+ @augeas.expects(:insert).with("/Jar/Jar", "Binks", false)
+ @augeas.expects(:save).returns(true)
+ @provider.execute_changes.should == :executed
+ end
+
it "should handle multiple commands" do
- command = [["ins", "/Jar/Jar"], ["clear", "/Jar/Jar"]]
+ command = [["ins", "Binks", "after /Jar/Jar"], ["clear", "/Jar/Jar"]]
context = "/foo"
@resource.expects(:[]).times(2).returns(command).then.returns(context)
- @augeas.expects(:insert).with("/foo/Jar/Jar")
- @augeas.expects(:clear).with("/foo/Jar/Jar")
+ @augeas.expects(:insert).with("/foo/Jar/Jar", "Binks", false)
+ @augeas.expects(:clear).with("/foo/Jar/Jar")
@augeas.expects(:save).returns(true)
@provider.execute_changes.should == :executed
end
diff --git a/spec/unit/provider/parsedfile.rb b/spec/unit/provider/parsedfile.rb
index 05e9de3ab..11a91c8d7 100755
--- a/spec/unit/provider/parsedfile.rb
+++ b/spec/unit/provider/parsedfile.rb
@@ -47,4 +47,40 @@ describe Puppet::Provider::ParsedFile do
@class.instances
end
end
+
+ describe "when flushing a file's records to disk" do
+ before do
+ # This way we start with some @records, like we would in real life.
+ @class.stubs(:retrieve).returns []
+ @class.default_target = "/foo/bar"
+ @class.initvars
+ @class.prefetch
+
+ @filetype = mock 'filetype'
+ Puppet::Util::FileType.filetype(:flat).expects(:new).with("/my/file").returns @filetype
+
+ @filetype.stubs(:write)
+ end
+
+ it "should back up the file being written" do
+ @filetype.expects(:backup)
+
+ @class.flush_target("/my/file")
+ end
+
+ it "should not back up the file more than once between calls to 'prefetch'" do
+ @filetype.expects(:backup).once
+
+ @class.flush_target("/my/file")
+ @class.flush_target("/my/file")
+ end
+
+ it "should back the file up again once the file has been reread" do
+ @filetype.expects(:backup).times(2)
+
+ @class.flush_target("/my/file")
+ @class.prefetch
+ @class.flush_target("/my/file")
+ end
+ end
end
diff --git a/spec/unit/util/autoload.rb b/spec/unit/util/autoload.rb
new file mode 100755
index 000000000..ff717d6c5
--- /dev/null
+++ b/spec/unit/util/autoload.rb
@@ -0,0 +1,39 @@
+#!/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/util/autoload'
+
+describe Puppet::Util::Autoload do
+ before do
+ @autoload = Puppet::Util::Autoload.new("foo", "tmp")
+
+ @autoload.stubs(:eachdir).yields "/my/dir"
+ end
+
+ describe "when loading a file" do
+ [RuntimeError, LoadError, SyntaxError].each do |error|
+ it "should not die an if a #{error.to_s} exception is thrown" do
+ FileTest.stubs(:exists?).returns true
+
+ Kernel.expects(:load).raises error
+
+ lambda { @autoload.load("foo") }.should_not raise_error
+ end
+ end
+ end
+
+ describe "when loading all files" do
+ before do
+ Dir.stubs(:glob).returns "file.rb"
+ end
+
+ [RuntimeError, LoadError, SyntaxError].each do |error|
+ it "should not die an if a #{error.to_s} exception is thrown" do
+ Kernel.expects(:require).raises error
+
+ lambda { @autoload.loadall }.should_not raise_error
+ end
+ end
+ end
+end
diff --git a/spec/unit/util/filetype.rb b/spec/unit/util/filetype.rb
new file mode 100644
index 000000000..0506b6b47
--- /dev/null
+++ b/spec/unit/util/filetype.rb
@@ -0,0 +1,110 @@
+#!/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/util/filetype'
+
+# XXX Import all of the tests into this file.
+describe Puppet::Util::FileType do
+ describe "when backing up a file" do
+ before do
+ @file = Puppet::Util::FileType.filetype(:flat).new("/my/file")
+ end
+
+ it "should do nothing if the file does not exist" do
+ File.expects(:exists?).with("/my/file").returns false
+ @file.expects(:bucket).never
+ @file.backup
+ end
+
+ it "should use its filebucket to backup the file if it exists" do
+ File.expects(:exists?).with("/my/file").returns true
+
+ bucket = mock 'bucket'
+ bucket.expects(:backup).with("/my/file")
+
+ @file.expects(:bucket).returns bucket
+ @file.backup
+ end
+
+ it "should use the filebucket named 'puppet' if it finds one" do
+ bucket = mock 'bucket'
+ bucket.expects(:bucket).returns "mybucket"
+
+ Puppet::Type.type(:filebucket).expects(:[]).with("puppet").returns bucket
+
+ @file.bucket.should == "mybucket"
+ end
+
+ it "should use the default filebucket if none named 'puppet' is found" do
+ bucket = mock 'bucket'
+ bucket.expects(:bucket).returns "mybucket"
+
+ Puppet::Type.type(:filebucket).expects(:[]).with("puppet").returns nil
+ Puppet::Type.type(:filebucket).expects(:mkdefaultbucket).returns bucket
+
+ @file.bucket.should == "mybucket"
+ end
+ end
+
+ describe "the flat filetype" do
+ before do
+ @type = Puppet::Util::FileType.filetype(:flat)
+ end
+ it "should exist" do
+ @type.should_not be_nil
+ end
+
+ describe "when the file already exists" do
+ it "should return the file's contents when asked to read it" do
+ file = @type.new("/my/file")
+ File.expects(:exist?).with("/my/file").returns true
+ File.expects(:read).with("/my/file").returns "my text"
+
+ file.read.should == "my text"
+ end
+
+ it "should unlink the file when asked to remove it" do
+ file = @type.new("/my/file")
+ File.expects(:exist?).with("/my/file").returns true
+ File.expects(:unlink).with("/my/file")
+
+ file.remove
+ end
+ end
+
+ describe "when the file does not exist" do
+ it "should return an empty string when asked to read the file" do
+ file = @type.new("/my/file")
+ File.expects(:exist?).with("/my/file").returns false
+
+ file.read.should == ""
+ end
+ end
+
+ describe "when writing the file" do
+ before do
+ @file = @type.new("/my/file")
+ FileUtils.stubs(:cp)
+
+ @tempfile = stub 'tempfile', :print => nil, :close => nil, :flush => nil, :path => "/other/file"
+ Tempfile.stubs(:new).returns @tempfile
+ end
+
+ it "should first create a temp file and copy its contents over to the file location" do
+ Tempfile.expects(:new).with("puppet").returns @tempfile
+ @tempfile.expects(:print).with("my text")
+ @tempfile.expects(:flush)
+ @tempfile.expects(:close)
+ FileUtils.expects(:cp).with(@tempfile.path, "/my/file")
+
+ @file.write "my text"
+ end
+
+ it "should set the selinux default context on the file" do
+ @file.expects(:set_selinux_default_context).with("/my/file")
+ @file.write "eh"
+ end
+ end
+ end
+end
diff --git a/test/util/filetype.rb b/test/util/filetype.rb
deleted file mode 100755
index 24a968552..000000000
--- a/test/util/filetype.rb
+++ /dev/null
@@ -1,137 +0,0 @@
-#!/usr/bin/env ruby
-
-require File.dirname(__FILE__) + '/../lib/puppettest'
-
-require 'puppettest'
-require 'puppet/util/filetype'
-require 'mocha'
-
-class TestFileType < Test::Unit::TestCase
- include PuppetTest
-
- def test_flat
- obj = nil
- path = tempfile()
- type = nil
-
- assert_nothing_raised {
- type = Puppet::Util::FileType.filetype(:flat)
- }
-
- assert(type, "Could not retrieve flat filetype")
-
- assert_nothing_raised {
- obj = type.new(path)
- }
-
- text = "This is some text\n"
-
- newtext = nil
- assert_nothing_raised {
- newtext = obj.read
- }
-
- # The base class doesn't allow a return of nil
- assert_equal("", newtext, "Somehow got some text")
-
- assert_nothing_raised {
- obj.write(text)
- }
- assert_nothing_raised {
- newtext = obj.read
- }
-
- assert_equal(text, newtext, "Text was changed somehow")
-
- File.open(path, "w") { |f| f.puts "someyayness" }
-
- text = File.read(path)
- assert_nothing_raised {
- newtext = obj.read
- }
-
- assert_equal(text, newtext, "Text was changed somehow")
- end
-
- # Make sure that modified files are backed up before they're changed.
- def test_backup_is_called
- path = tempfile
- File.open(path, "w") { |f| f.print 'yay' }
-
- obj = Puppet::Util::FileType.filetype(:flat).new(path)
-
- obj.expects(:backup)
-
- obj.write("something")
-
- assert_equal("something", File.read(path), "File did not get changed")
- end
-
- def test_backup
- path = tempfile
- type = Puppet::Type.type(:filebucket)
-
- obj = Puppet::Util::FileType.filetype(:flat).new(path)
-
- # First try it when the file does not yet exist.
- assert_nothing_raised("Could not call backup when file does not exist") do
- obj.backup
- end
-
- # Then create the file
- File.open(path, "w") { |f| f.print 'one' }
-
- # Then try it with no filebucket objects
- assert_nothing_raised("Could not call backup with no buckets") do
- obj.backup
- end
- puppet = type.mkdefaultbucket
- assert(puppet, "Did not create default filebucket")
-
- assert_equal("one", puppet.bucket.getfile(Digest::MD5.hexdigest(File.read(path))), "Could not get file from backup")
-
- # Try it again when the default already exists
- File.open(path, "w") { |f| f.print 'two' }
- assert_nothing_raised("Could not call backup with no buckets") do
- obj.backup
- end
-
- assert_equal("two", puppet.bucket.getfile(Digest::MD5.hexdigest(File.read(path))), "Could not get file from backup")
- end
-
- if Facter["operatingsystem"].value == "Darwin" and Facter["operatingsystemrelease"] != "9.1.0"
- def test_ninfotoarray
- obj = nil
- type = nil
-
- assert_nothing_raised {
- type = Puppet::Util::FileType.filetype(:netinfo)
- }
-
- assert(type, "Could not retrieve netinfo filetype")
- %w{users groups aliases}.each do |map|
- assert_nothing_raised {
- obj = type.new(map)
- }
-
- assert_nothing_raised("could not read map %s" % map) {
- obj.read
- }
-
- array = nil
-
- assert_nothing_raised("Failed to parse %s map" % map) {
- array = obj.to_array
- }
-
- assert_instance_of(Array, array)
-
- array.each do |record|
- assert_instance_of(Hash, record)
- assert(record.length != 0)
- end
- end
- end
- end
-end
-