Adds a new resource type to puppet for web requests
and implements a provider of that type using the
ruby curl interface provided by the 'curb' rubygem
This is the first revision of the patch I had previous sent out,
containing improved validations, methods in the global namespace
being encapsulated in the type/provider, the re-renaming of 'web
request' back to 'web' so as to better represent the 'web resource'
Signed-off-by: Mo Morsi <[email protected]>
---
Local-branch: feature/master/7474
lib/puppet/external/curl.rb | 47 ++++++++++++++
lib/puppet/provider/web/curl.rb | 131 +++++++++++++++++++++++++++++++++++++++
lib/puppet/type/web.rb | 96 ++++++++++++++++++++++++++++
3 files changed, 274 insertions(+), 0 deletions(-)
create mode 100644 lib/puppet/external/curl.rb
create mode 100644 lib/puppet/provider/web/curl.rb
create mode 100644 lib/puppet/type/web.rb
diff --git a/lib/puppet/external/curl.rb b/lib/puppet/external/curl.rb
new file mode 100644
index 0000000..ab189c8
--- /dev/null
+++ b/lib/puppet/external/curl.rb
@@ -0,0 +1,47 @@
+# Provides an interface to curl using the curb gem for puppet
+require 'curb'
+
+class Curl::Easy
+
+ def self.web_request(method, uri, request_params, params = {})
+ raise Puppet::Error, "Must specify http method (#{method}) and uri
(#{uri})" if method.nil? || uri.nil?
+
+ curl = self.new
+
+ if params.has_key?(:cookie)
+ curl.enable_cookies = true
+ curl.cookiefile = params[:cookie]
+ curl.cookiejar = params[:cookie]
+ end
+
+ curl.follow_location = (params.has_key?(:follow) && params[:follow])
+
+ case(method)
+ when 'get'
+ url = uri
+ url += ";" + request_params.collect { |k,v| "#{k}=#{v}" }.join("&")
unless request_params.nil?
+ curl.url = url
+ curl.http_get
+ return curl
+
+ when 'post'
+ cparams = []
+ request_params.each_pair { |k,v| cparams << Curl::PostField.content(k,v)
} unless request_params.nil?
+ curl.url = uri
+ curl.http_post(cparams)
+ return curl
+
+ #when 'put'
+ #when 'delete'
+ end
+ end
+
+ def valid_status_code?(valid_values=[])
+ valid_values.include?(response_code.to_s)
+ end
+
+ def valid_response_body?(test=/.*/)
+ body_str =~ Regexp.new(test)
+ end
+
+end
diff --git a/lib/puppet/provider/web/curl.rb b/lib/puppet/provider/web/curl.rb
new file mode 100644
index 0000000..e84fe02
--- /dev/null
+++ b/lib/puppet/provider/web/curl.rb
@@ -0,0 +1,131 @@
+require 'uuid'
+require 'fileutils'
+require 'puppet/external/curl'
+
+# Puppet provider definition
+Puppet::Type.type(:web).provide :curl do
+ desc "Use curl to access web resources"
+
+ def get
+ @uri
+ end
+
+ def post
+ @uri
+ end
+
+ def delete
+ @uri
+ end
+
+ def put
+ @uri
+ end
+
+ def get=(uri)
+ @uri = uri
+ process_params('get', @resource, uri)
+ end
+
+ def post=(uri)
+ @uri = uri
+ process_params('post', @resource, uri)
+ end
+
+ def delete=(uri)
+ @uri = uri
+ process_params('delete', @resource, uri)
+ end
+
+ def put=(uri)
+ @uri = uri
+ process_params('put', @resource, uri)
+ end
+
+ private
+
+ # Helper to process/parse web parameters
+ def process_params(request_method, params, uri)
+ begin
+ # Set request method and generate a unique session key
+ session = "/tmp/#{UUID.new.generate}"
+
+ # Invoke a login request if necessary
+ session_request(params[:login]['http_method'], params[:login]['uri'],
session,
+ params[:login].reject{ |k,v| k == 'http_method' || k ==
'uri' },
+ params ) if params[:login]
+
+
+ # Check to see if we should actually run the request
+ return if params[:if] &&
+ skip_request?(params[:if]['http_method'], params[:if]['uri'],
session,
+ params[:if]['parameters'], params[:if])
+
+ return if params[:unless] &&
+ !skip_request?(params[:unless]['http_method'],
params[:unless]['uri'], session,
+ params[:unless]['parameters'], params[:unless])
+
+ # Actually run the request and verify the result
+ result = Curl::Easy::web_request(request_method, uri,
params[:parameters],
+ :cookie => session, :follow =>
params[:follow])
+ verify_result(result,
+ :returns => params[:returns],
+ :body => params[:verify])
+ result.close
+
+ # Invoke a logout request if necessary
+ session_request(params[:logout]['http_method'], params[:logout]['uri'],
session,
+ params[:logout].reject{ |k,v| k == 'http_method' || k ==
'uri' },
+ params ) if params[:logout]
+
+ rescue Exception => e
+ raise Puppet::Error, "An exception was raised when invoking web request:
#{e}"
+
+ ensure
+ FileUtils.rm_f(session) if params[:logout]
+ end
+ end
+
+ # Helper to issue login/logout requests
+ def session_request(http_method, uri, session, request_params, params = {})
+ Curl::Easy::web_request(http_method, uri, request_params,
+ :cookie => session, :follow =>
params[:follow]).close
+
+ end
+
+ # Helper to issue request to query if we should skip main request or not
+ def skip_request?(http_method, uri, session, request_params, params = {})
+ result = Curl::Easy::web_request(http_method, uri, request_params,
+ :cookie => session, :follow =>
params[:follow])
+
+ begin
+ verify_result(result,
+ :returns => params['returns'],
+ :body => params['verify'])
+
+ rescue Puppet::Error => e
+ return true
+
+ ensure
+ result.close
+ end
+
+ return false
+ end
+
+ # Helper to verify the response
+ def verify_result(result, verify = {})
+ if verify.has_key?(:returns) && !verify[:returns].nil? &&
+ !result.valid_status_code?(verify[:returns])
+ raise Puppet::Error, "Invalid HTTP Return Code:
#{result.response_code},
+ was expecting one of #{verify[:returns].join(",
")}"
+ end
+
+ if verify.has_key?(:body) && !verify[:body].nil? &&
+ !result.valid_response_body?(verify[:body])
+ raise Puppet::Error, "Expecting #{verify[:body]} in the result"
+ end
+ end
+
+
+end
diff --git a/lib/puppet/type/web.rb b/lib/puppet/type/web.rb
new file mode 100644
index 0000000..a9e912c
--- /dev/null
+++ b/lib/puppet/type/web.rb
@@ -0,0 +1,96 @@
+require 'uri'
+
+Puppet::Type.newtype(:web) do
+ @doc = "Issue a request to a resource on the world wide web"
+
+ private
+
+ def self.validate_uri(url)
+ begin
+ uri = URI.parse(url)
+ raise ArgumentError, "Specified uri #{url} is not valid" if
![URI::HTTP, URI::HTTPS].include?(uri.class)
+ rescue URI::InvalidURIError
+ raise ArgumentError, "Specified uri #{url} is not valid"
+ end
+ end
+
+ def self.validate_http_status(status)
+ status = [status] unless status.is_a?(Array)
+ status.each { |stat|
+ stat = stat.to_s
+ unless ['100', '101', '102', '122',
+ '200', '201', '202', '203', '204', '205', '206', '207', '226',
+ '300', '301', '302', '303', '304', '305', '306', '307',
+ '400', '401', '402', '403', '404', '405', '406', '407', '408',
'409',
+ '410', '411', '412', '413', '414', '415', '416', '417', '418',
+ '422', '423', '424', '425', '426', '444', '449', '450', '499',
+ '500', '501', '502', '503', '504', '505', '506', '507', '508',
' 509', '510'
+ ].include?(stat)
+ raise ArgumentError, "Invalid http status code #{stat} specified"
+ end
+ }
+ end
+
+ newparam :name
+
+ newproperty(:get) do
+ desc "Issue get request to the specified uri"
+ validate do |value| Puppet::Type::Web.validate_uri(value) end
+ end
+
+ newproperty(:post) do
+ desc "Issue post request to the specified uri"
+ validate do |value| Puppet::Type::Web.validate_uri(value) end
+ end
+
+ newproperty(:delete) do
+ desc "Issue delete request to the specified uri"
+ validate do |value| Puppet::Type::Web.validate_uri(value) end
+ end
+
+ newproperty(:put) do
+ desc "Issue put request to the specified uri"
+ validate do |value| Puppet::Type::Web.validate_uri(value) end
+ end
+
+ newparam(:parameters) do
+ desc "Hash of parameters to include in the web request"
+ validate do |value| Puppet::Type::Web.validate_uri(value) end
+ end
+
+ newparam(:returns) do
+ desc "Expected http return codes of the request"
+ defaultto ["200"]
+ validate do |value| Puppet::Type::Web.validate_http_status(value) end
+ munge do |value|
+ value = [value] unless value.is_a?(Array)
+ value = value.collect { |val| val.to_s }
+ value
+ end
+ end
+
+ newparam(:follow) do
+ desc "Boolean indicating if redirects should be followed"
+ newvalues(:true, :false)
+ end
+
+ newparam(:verify) do
+ desc "String to verify as being part of the result"
+ end
+
+ newparam(:login) do
+ desc "Login parameters to be used if a login is required before making
the request"
+ end
+
+ newparam(:logout) do
+ desc "Logout parameters to be used if a logout is requred after making
the request"
+ end
+
+ newparam(:unless) do
+ desc "Do not run request if the request specified here succeeds"
+ end
+
+ newparam(:if) do
+ desc "Only run request if the request specified here succeeds"
+ end
+end
--
1.7.2.3
--
You received this message because you are subscribed to the Google Groups
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/puppet-dev?hl=en.