summaryrefslogtreecommitdiffstats
path: root/lib/puppet/indirector/rest.rb
blob: 127eb7110195f88b8120b107b5ff2a13daedd7a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
require 'net/http'
require 'uri'

require 'puppet/network/http_pool'
require 'puppet/network/http/api/v1'
require 'puppet/network/http/compression'

# Access objects via REST
class Puppet::Indirector::REST < Puppet::Indirector::Terminus
    include Puppet::Network::HTTP::API::V1
    include Puppet::Network::HTTP::Compression.module

    class << self
        attr_reader :server_setting, :port_setting
    end

    # Specify the setting that we should use to get the server name.
    def self.use_server_setting(setting)
        @server_setting = setting
    end

    def self.server
        Puppet.settings[server_setting || :server]
    end

    # Specify the setting that we should use to get the port.
    def self.use_port_setting(setting)
        @port_setting = setting
    end

    def self.port
        Puppet.settings[port_setting || :masterport].to_i
    end

    # Figure out the content type, turn that into a format, and use the format
    # to extract the body of the response.
    def deserialize(response, multiple = false)
        case response.code
        when "404"
            return nil
        when /^2/
            raise "No content type in http response; cannot parse" unless response['content-type']

            content_type = response['content-type'].gsub(/\s*;.*$/,'') # strip any appended charset

            body = uncompress_body(response)

            # Convert the response to a deserialized object.
            if multiple
                model.convert_from_multiple(content_type, body)
            else
                model.convert_from(content_type, body)
            end
        else
            # Raise the http error if we didn't get a 'success' of some kind.
            message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
            raise Net::HTTPError.new(message, response)
        end
    end

    # Provide appropriate headers.
    def headers
        add_accept_encoding({"Accept" => model.supported_formats.join(", ")})
    end

    def network(request)
        Puppet::Network::HttpPool.http_instance(request.server || self.class.server, request.port || self.class.port)
    end

    def find(request)
        return nil unless result = deserialize(network(request).get(indirection2uri(request), headers))
        result.name = request.key if result.respond_to?(:name=)
        result
    end

    def search(request)
        unless result = deserialize(network(request).get(indirection2uri(request), headers), true)
            return []
        end
        result
    end

    def destroy(request)
        raise ArgumentError, "DELETE does not accept options" unless request.options.empty?
        deserialize network(request).delete(indirection2uri(request), headers)
    end

    def save(request)
        raise ArgumentError, "PUT does not accept options" unless request.options.empty?
        deserialize network(request).put(indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime }))
    end

    private

    def environment
        Puppet::Node::Environment.new
    end
end