#
# @api private
#
# Represents a puppet web service
#
class Puppet::HTTP::Service
# @api private
# @return [URI] the url associated with this service
attr_reader :url
# @api private
# @return [Array<Symbol>] available services
SERVICE_NAMES = [:ca, :fileserver, :puppet, :puppetserver, :report].freeze
# @api private
# @return [Array<Symbol>] format types that are unsupported
EXCLUDED_FORMATS = [:yaml, :b64_zlib_yaml, :dot].freeze
#
# @api private
#
# Create a new web service, which contains the URL used to connect to the
# service. The four services implemented are `:ca`, `:fileserver`, `:puppet`,
# and `:report`.
#
# The `:ca` and `:report` services handle certs and reports, respectively. The
# `:fileserver` service handles puppet file metadata and content requests. And
# the default service, `:puppet`, handles nodes, facts, and catalogs.
#
# @param [Puppet::HTTP::Client] client the owner of the session
# @param [Puppet::HTTP::Session] session the owner of the service
# @param [Symbol] name the type of service to create
# @param [<Type>] server optional, the server to connect to
# @param [<Type>] port optional, the port to connect to
#
# @return [Puppet::HTTP::Service] an instance of the service type requested
#
def self.create_service(client, session, name, server = nil, port = nil)
case name
when :ca
Puppet::HTTP::Service::Ca.new(client, session, server, port)
when :fileserver
Puppet::HTTP::Service::FileServer.new(client, session, server, port)
when :puppet
::Puppet::HTTP::Service::Compiler.new(client, session, server, port)
when :puppetserver
::Puppet::HTTP::Service::Puppetserver.new(client, session, server, port)
when :report
Puppet::HTTP::Service::Report.new(client, session, server, port)
else
raise ArgumentError, "Unknown service #{name}"
end
end
#
# @api private
#
# Check if the service named is included in the list of available services.
#
# @param [Symbol] name
#
# @return [Boolean]
#
def self.valid_name?(name)
SERVICE_NAMES.include?(name)
end
#
# @api private
#
# Create a new service
#
# @param [Puppet::HTTP::Client] client
# @param [Puppet::HTTP::Session] session
# @param [URI] url The url to connect to
#
def initialize(client, session, url)
@client = client
@session = session
@url = url
end
#
# @api private
#
# Return the url with the given path encoded and appended
#
# @param [String] path the string to append to the base url
#
# @return [URI] the URI object containing the encoded path
#
def with_base_url(path)
u = @url.dup
u.path += Puppet::Util.uri_encode(path)
u
end
#
# @api private
#
# Open a connection using the given ssl context
#
# @param [Puppet::SSL::SSLContext] ssl_context (nil) optional ssl context to
# connect with
#
def connect(ssl_context: nil)
@client.connect(@url, options: {ssl_context: ssl_context})
end
protected
def add_puppet_headers(headers)
modified_headers = headers.dup
# Add 'X-Puppet-Profiling' to enable performance profiling if turned on
modified_headers['X-Puppet-Profiling'] = 'true' if Puppet[:profile]
# Add additional user-defined headers if they are defined
Puppet[:http_extra_headers].each do |name, value|
if modified_headers.keys.find { |key| key.casecmp(name) == 0 }
Puppet.warning(_('Ignoring extra header "%{name}" as it was previously set.') % { name: name })
else
if value.nil? || value.empty?
Puppet.warning(_('Ignoring extra header "%{name}" as it has no value.') % { name: name })
else
modified_headers[name] = value
end
end
end
modified_headers
end
def build_url(api, server, port)
URI::HTTPS.build(host: server,
port: port,
path: api
).freeze
end
def get_mime_types(model)
network_formats = model.supported_formats - EXCLUDED_FORMATS
network_formats.map { |f| model.get_format(f).mime }
end
def formatter_for_response(response)
header = response['Content-Type']
raise Puppet::HTTP::ProtocolError.new(_("No content type in http response; cannot parse")) unless header
header.gsub!(/\s*;.*$/,'') # strip any charset
formatter = Puppet::Network::FormatHandler.mime(header)
raise Puppet::HTTP::ProtocolError.new("Content-Type is unsupported") if EXCLUDED_FORMATS.include?(formatter.name)
formatter
end
def serialize(formatter, object)
begin
formatter.render(object)
rescue => err
raise Puppet::HTTP::SerializationError.new("Failed to serialize #{object.class} to #{formatter.name}: #{err.message}", err)
end
end
def serialize_multiple(formatter, object)
begin
formatter.render_multiple(object)
rescue => err
raise Puppet::HTTP::SerializationError.new("Failed to serialize multiple #{object.class} to #{formatter.name}: #{err.message}", err)
end
end
def deserialize(response, model)
formatter = formatter_for_response(response)
begin
formatter.intern(model, response.body.to_s)
rescue => err
raise Puppet::HTTP::SerializationError.new("Failed to deserialize #{model} from #{formatter.name}: #{err.message}", err)
end
end
def deserialize_multiple(response, model)
formatter = formatter_for_response(response)
begin
formatter.intern_multiple(model, response.body.to_s)
rescue => err
raise Puppet::HTTP::SerializationError.new("Failed to deserialize multiple #{model} from #{formatter.name}: #{err.message}", err)
end
end
def process_response(response)
@session.process_response(response)
raise Puppet::HTTP::ResponseError.new(response) unless response.success?
end
end
Copyright 2K16 - 2K18 Indonesian Hacker Rulez