Current File : //opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/indirector/request.rb |
require 'cgi'
require 'uri'
require_relative '../../puppet/indirector'
require_relative '../../puppet/util/psych_support'
require_relative '../../puppet/util/warnings'
# This class encapsulates all of the information you need to make an
# Indirection call, and as a result also handles REST calls. It's somewhat
# analogous to an HTTP Request object, except tuned for our Indirector.
class Puppet::Indirector::Request
include Puppet::Util::PsychSupport
include Puppet::Util::Warnings
attr_accessor :key, :method, :options, :instance, :node, :ip, :authenticated, :ignore_cache, :ignore_cache_save, :ignore_terminus
attr_accessor :server, :port, :uri, :protocol
attr_reader :indirection_name
# trusted_information is specifically left out because we can't serialize it
# and keep it "trusted"
OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :ignore_cache_save, :instance, :environment]
# Is this an authenticated request?
def authenticated?
# Double negative, so we just get true or false
! ! authenticated
end
def environment
# If environment has not been set directly, we should use the application's
# current environment
@environment ||= Puppet.lookup(:current_environment)
end
def environment=(env)
@environment =
if env.is_a?(Puppet::Node::Environment)
env
else
Puppet.lookup(:environments).get!(env)
end
end
# LAK:NOTE This is a messy interface to the cache, and it's only
# used by the Configurer class. I decided it was better to implement
# it now and refactor later, when we have a better design, than
# to spend another month coming up with a design now that might
# not be any better.
def ignore_cache?
ignore_cache
end
def ignore_cache_save?
ignore_cache_save
end
def ignore_terminus?
ignore_terminus
end
def initialize(indirection_name, method, key, instance, options = {})
@instance = instance
options ||= {}
self.indirection_name = indirection_name
self.method = method
options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash }
set_attributes(options)
@options = options
if key
# If the request key is a URI, then we need to treat it specially,
# because it rewrites the key. We could otherwise strip server/port/etc
# info out in the REST class, but it seemed bad design for the REST
# class to rewrite the key.
if key.to_s =~ /^\w+:\// and not Puppet::Util.absolute_path?(key.to_s) # it's a URI
set_uri_key(key)
else
@key = key
end
end
@key = @instance.name if ! @key and @instance
end
# Look up the indirection based on the name provided.
def indirection
Puppet::Indirector::Indirection.instance(indirection_name)
end
def indirection_name=(name)
@indirection_name = name.to_sym
end
def model
ind = indirection
raise ArgumentError, _("Could not find indirection '%{indirection}'") % { indirection: indirection_name } unless ind
ind.model
end
# Are we trying to interact with multiple resources, or just one?
def plural?
method == :search
end
def initialize_from_hash(hash)
@indirection_name = hash['indirection_name'].to_sym
@method = hash['method'].to_sym
@key = hash['key']
@instance = hash['instance']
@options = hash['options']
end
def to_data_hash
{ 'indirection_name' => @indirection_name.to_s,
'method' => @method.to_s,
'key' => @key,
'instance' => @instance,
'options' => @options }
end
def to_hash
result = options.dup
OPTION_ATTRIBUTES.each do |attribute|
value = send(attribute)
if value
result[attribute] = value
end
end
result
end
def description
return(uri ? uri : "/#{indirection_name}/#{key}")
end
def remote?
self.node or self.ip
end
private
def set_attributes(options)
OPTION_ATTRIBUTES.each do |attribute|
if options.include?(attribute.to_sym)
send(attribute.to_s + "=", options[attribute])
options.delete(attribute)
end
end
end
# Parse the key as a URI, setting attributes appropriately.
def set_uri_key(key)
@uri = key
begin
# calling uri_encode for UTF-8 characters will % escape them and keep them UTF-8
uri = URI.parse(Puppet::Util.uri_encode(key))
rescue => detail
raise ArgumentError, _("Could not understand URL %{key}: %{detail}") % { key: key, detail: detail }, detail.backtrace
end
# Just short-circuit these to full paths
if uri.scheme == "file"
@key = Puppet::Util.uri_to_path(uri)
return
end
@server = uri.host if uri.host && !uri.host.empty?
# If the URI class can look up the scheme, it will provide a port,
# otherwise it will default to '0'.
if uri.port.to_i == 0 and uri.scheme == "puppet"
@port = Puppet.settings[:serverport].to_i
else
@port = uri.port.to_i
end
# filebucket:// is only used internally to pass request details
# from Dipper objects to the indirector. The wire always uses HTTPS.
if uri.scheme == 'filebucket'
@protocol = 'https'
else
@protocol = uri.scheme
end
@key = Puppet::Util.uri_unescape(uri.path.sub(/^\//, ''))
end
end