diff options
-rw-r--r-- | lib/puppet/indirector/rest.rb | 2 | ||||
-rw-r--r-- | lib/puppet/network/http/mongrel/rest.rb | 19 | ||||
-rw-r--r-- | lib/puppet/network/http/webrick/rest.rb | 7 | ||||
-rw-r--r-- | lib/puppet/parser/functions/regsubst.rb | 74 | ||||
-rw-r--r-- | lib/puppet/util/selinux.rb | 19 | ||||
-rwxr-xr-x | spec/unit/indirector/rest.rb | 40 | ||||
-rwxr-xr-x | spec/unit/parser/functions/regsubst.rb | 80 |
7 files changed, 181 insertions, 60 deletions
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb index 35847de88..e1ee89f04 100644 --- a/lib/puppet/indirector/rest.rb +++ b/lib/puppet/indirector/rest.rb @@ -51,7 +51,7 @@ class Puppet::Indirector::REST < Puppet::Indirector::Terminus end else # Raise the http error if we didn't get a 'success' of some kind. - message = "Error %s on SERVER: %s" % [response.code, response.message] + message = "Error %s on SERVER: %s" % [response.code, (response.body||'').empty? ? response.message : response.body] raise Net::HTTPError.new(message, response) end end diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb index 8a4de1cce..7b28d880b 100644 --- a/lib/puppet/network/http/mongrel/rest.rb +++ b/lib/puppet/network/http/mongrel/rest.rb @@ -50,16 +50,17 @@ class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler # produce the body of the response def set_response(response, result, status = 200) - args = [status] - # Set the 'reason' (or 'message', as it's called in Webrick), when - # we have a failure. - if status >= 300 - args << false << result - end - - response.start(*args) do |head, body| - body.write(result) + # we have a failure, unless we're on a version of mongrel that doesn't + # support this. + if status < 300 + response.start(status) { |head, body| body.write(result) } + else + begin + response.start(status,false,result) { |head, body| body.write(result) } + rescue ArgumentError + response.start(status) { |head, body| body.write(result) } + end end end diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb index 287fa39ac..274665dcd 100644 --- a/lib/puppet/network/http/webrick/rest.rb +++ b/lib/puppet/network/http/webrick/rest.rb @@ -50,11 +50,8 @@ class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet def set_response(response, result, status = 200) response.status = status - if status >= 200 and status < 300 - response.body = result - else - response.reason_phrase = result - end + response.body = result if status >= 200 and status != 304 + response.reason_phrase = result if status < 200 or status >= 300 end # Retrieve node/cert/ip information from the request object. diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb index e6b98eb2c..d02680862 100644 --- a/lib/puppet/parser/functions/regsubst.rb +++ b/lib/puppet/parser/functions/regsubst.rb @@ -1,22 +1,22 @@ module Puppet::Parser::Functions newfunction(:regsubst, :type => :rvalue, :doc => " - Perform regexp replacement on a string. + Perform regexp replacement on a string or array of strings. - **Parameters** (in order): -:str: The string to operate on. +:target: The string or array of strings to operate on. If an array, the replacement will be performed on each of the elements in the array, and the return value will be an array. -:regexp: The regular expression matching the string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself. +:regexp: The regular expression matching the target string. If you want it anchored at the start and or end of the string, you must do that with ^ and $ yourself. -:replacement: Replacement string. Can contain back references to what was matched using 0, 1, and so on. +:replacement: Replacement string. Can contain back references to what was matched using \\0, \\1, and so on. :flags: Optional. String of single letter flags for how the regexp is interpreted: - **E** Extended regexps - **I** Ignore case in regexps - **M** Multiline regexps - - **G** Global replacement; all occurrences of the regexp in the string will be replaced. Without this, only the first occurrence will be replaced. + - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced. :lang: Optional. How to handle multibyte characters. A single-character string with the following values: @@ -35,36 +35,50 @@ 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)") + do |args| + unless args.length.between?(3, 5) + raise(Puppet::ParseError, + "regsubst(): got #{args.length} arguments, expected 3 to 5") end - str, regexp, replacement, flags, lang = args + target, 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 + operation = :sub + if flags == nil + flags = [] + elsif flags.respond_to?(:split) + flags = flags.split('') + else + raise(Puppet::ParseError, + "regsubst(): bad flags parameter #{flags.class}:`#{flags}'") + end + flags.each do |f| + case f + when 'G' then operation = :gsub + when 'E' then reflags |= Regexp::EXTENDED + when 'I' then reflags |= Regexp::IGNORECASE + when 'M' then reflags |= Regexp::MULTILINE + else raise(Puppet::ParseError, "regsubst(): bad flag `#{f}'") end end - re = Regexp.compile(regexp, reflags, lang) - if global - result = str.gsub(re, replacement) + begin + re = Regexp.compile(regexp, reflags, lang) + rescue RegexpError, TypeError + raise(Puppet::ParseError, + "regsubst(): Bad regular expression `#{regexp}'") + end + if target.respond_to?(operation) + # String parameter -> string result + result = target.send(operation, re, replacement) + elsif target.respond_to?(:collect) and + target.respond_to?(:all?) and + target.all? { |e| e.respond_to?(operation) } + # Array parameter -> array result + result = target.collect { |e| + e.send(operation, re, replacement) + } else - result = str.sub(re, replacement) + raise(Puppet::ParseError, + "regsubst(): bad target #{target.class}:`#{target}'") end return result end diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb index fdd40a66f..348eab7e9 100644 --- a/lib/puppet/util/selinux.rb +++ b/lib/puppet/util/selinux.rb @@ -154,14 +154,21 @@ module Puppet::Util::SELinux def read_mounts mounts = "" begin - mountfh = File.open("/proc/mounts") - # We use read_nonblock() in a loop rather than read() to work-around - # a linux kernel bug. See ticket #1963 for details. - while true - mounts += mountfh.read_nonblock(1024) + if File.instance_methods.include? "read_nonblock" + # If possible we use read_nonblock() in a loop rather than read() to work- + # a linux kernel bug. See ticket #1963 for details. + mountfh = File.open("/proc/mounts") + mounts += mountfh.read_nonblock(1024) while true + end + else + # Otherwise we shell out and let cat do it for us + mountfh = IO.popen("/bin/cat /proc/mounts") + mounts = mountfh.read end - rescue EOFError + ensure mountfh.close + rescue EOFError + # that's expected rescue return nil end diff --git a/spec/unit/indirector/rest.rb b/spec/unit/indirector/rest.rb index a352f2a2a..d98e6f5c6 100755 --- a/spec/unit/indirector/rest.rb +++ b/spec/unit/indirector/rest.rb @@ -90,15 +90,37 @@ describe Puppet::Indirector::REST do @searcher.deserialize(response).should be_nil end - it "should fail if the response code is not in the 200s" do - @model.expects(:convert_from).never - - response = mock 'response' - response.stubs(:code).returns "300" - response.stubs(:message).returns "There was a problem" - - lambda { @searcher.deserialize(response) }.should raise_error(Net::HTTPError) - end + [300,400,403,405,500,501,502,503,504].each { |rc| + describe "when the response code is #{rc}" do + before :each do + @model.expects(:convert_from).never + + @response = mock 'response' + @response.stubs(:code).returns rc.to_s + @response.stubs(:message).returns "There was a problem (header)" + end + + it "should fail" do + @response.stubs(:body).returns nil + lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError) + end + + it "should take the error message from the body, if present" do + @response.stubs(:body).returns "There was a problem (body)" + lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (body)") + end + + it "should take the error message from the response header if the body is empty" do + @response.stubs(:body).returns "" + lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)") + end + + it "should take the error message from the response header if the body is absent" do + @response.stubs(:body).returns nil + lambda { @searcher.deserialize(@response) }.should raise_error(Net::HTTPError,"Error #{rc} on SERVER: There was a problem (header)") + end + end + } it "should return the results of converting from the format specified by the content-type header if the response code is in the 200s" do @model.expects(:convert_from).with("myformat", "mydata").returns "myobject" diff --git a/spec/unit/parser/functions/regsubst.rb b/spec/unit/parser/functions/regsubst.rb index 0e80ec798..5a533efb1 100755 --- a/spec/unit/parser/functions/regsubst.rb +++ b/spec/unit/parser/functions/regsubst.rb @@ -28,6 +28,26 @@ describe "the regsubst function" do raise_error(Puppet::ParseError)) end + it "should raise a ParseError for non-string and non-array target" do + lambda { @scope.function_regsubst([4711, "bar", "gazonk"]) }.should( + raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError for array target with non-string element" do + lambda { @scope.function_regsubst([["x", ["y"], "z"], "bar", "gazonk"]) }.should( + raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError for a bad regular expression" do + lambda { @scope.function_regsubst(["foo", "(bar", "gazonk"]) }.should( + raise_error(Puppet::ParseError)) + end + + it "should raise a ParseError for a non-string regular expression" do + lambda { @scope.function_regsubst(["foo", ["bar"], "gazonk"]) }.should( + raise_error(Puppet::ParseError)) + end + it "should handle groups" do result = @scope.function_regsubst( [ '130.236.254.10', @@ -85,4 +105,64 @@ describe "the regsubst function" do result.should(eql('<130>.<236>.<254>.<10>')) end + it "should apply on all elements of an array" do + data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] + result = @scope.function_regsubst([ data, '[.]', '-']) + result.should(eql( + ['130-236.254.10', 'foo-example.com', 'coconut', '10-20.30.40'])) + end + + it "should apply global substitutions on all elements of an array" do + data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] + result = @scope.function_regsubst([ data, '[.]', '-', 'G']) + result.should(eql( + ['130-236-254-10', 'foo-example-com', 'coconut', '10-20-30-40'])) + end + + it "should handle groups on all elements of an array" do + data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] + result = @scope.function_regsubst( + [ data, + '^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$', + '\4-\3-\2-\1' + ]) + result.should(eql( + ['10-254-236-130', 'foo.example.com', 'coconut', '40-30-20-10'])) + end + + it "should handle global substitutions with groups on all elements of an array" do + data = ['130.236.254.10', 'foo.example.com', 'coconut', '10.20.30.40'] + result = @scope.function_regsubst( + [ data, + '([^.]+)', + '<\1>', + 'G' + ]) + result.should(eql( + ['<130>.<236>.<254>.<10>', '<foo>.<example>.<com>', + '<coconut>', '<10>.<20>.<30>.<40>'])) + end + + it "should return an array (not a string) for a single element array parameter" do + data = ['130.236.254.10'] + result = @scope.function_regsubst( + [ data, + '([^.]+)', + '<\1>', + 'G' + ]) + result.should(eql(['<130>.<236>.<254>.<10>'])) + end + + it "should return a string (not a one element array) for a simple string parameter" do + data = '130.236.254.10' + result = @scope.function_regsubst( + [ data, + '([^.]+)', + '<\1>', + 'G' + ]) + result.should(eql('<130>.<236>.<254>.<10>')) + end + end |