puppet-rest 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +7 -0
  3. data/.pryrc +58 -0
  4. data/Gemfile +10 -0
  5. data/Gemfile.lock +73 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.md +81 -0
  8. data/Rakefile +3 -0
  9. data/lib/puppet-rest.rb +43 -0
  10. data/lib/puppet-rest/db/client.rb +42 -0
  11. data/lib/puppet-rest/db/config.rb +83 -0
  12. data/lib/puppet-rest/db/connection.rb +26 -0
  13. data/lib/puppet-rest/db/connection/fact-names.rb +9 -0
  14. data/lib/puppet-rest/db/connection/facts.rb +11 -0
  15. data/lib/puppet-rest/db/connection/nodes.rb +32 -0
  16. data/lib/puppet-rest/db/connection/resources.rb +11 -0
  17. data/lib/puppet-rest/db/entities/base.rb +100 -0
  18. data/lib/puppet-rest/db/entities/fact.rb +9 -0
  19. data/lib/puppet-rest/db/entities/node.rb +22 -0
  20. data/lib/puppet-rest/db/entities/resource.rb +12 -0
  21. data/lib/puppet-rest/db/request.rb +74 -0
  22. data/lib/puppet-rest/error.rb +42 -0
  23. data/lib/puppet-rest/identity_map.rb +4 -0
  24. data/lib/puppet-rest/monkey_patches/array.rb +7 -0
  25. data/lib/puppet-rest/monkey_patches/enumerable.rb +11 -0
  26. data/lib/puppet-rest/monkey_patches/hash.rb +49 -0
  27. data/lib/puppet-rest/monkey_patches/mash.rb +219 -0
  28. data/lib/puppet-rest/pe/client.rb +42 -0
  29. data/lib/puppet-rest/pe/config.rb +93 -0
  30. data/lib/puppet-rest/pe/connection.rb +25 -0
  31. data/lib/puppet-rest/pe/connection/ca_cert.rb +10 -0
  32. data/lib/puppet-rest/pe/connection/catalog.rb +10 -0
  33. data/lib/puppet-rest/pe/connection/node.rb +10 -0
  34. data/lib/puppet-rest/pe/entities/base.rb +100 -0
  35. data/lib/puppet-rest/pe/entities/catalog.rb +16 -0
  36. data/lib/puppet-rest/pe/entities/node.rb +9 -0
  37. data/lib/puppet-rest/pe/request.rb +77 -0
  38. data/lib/puppet-rest/response/client_error.rb +33 -0
  39. data/lib/puppet-rest/response/parse_json.rb +26 -0
  40. data/lib/puppet-rest/version.rb +3 -0
  41. data/puppet-rest.gemspec +28 -0
  42. data/spec/certificates/ca.pem +35 -0
  43. data/spec/certificates/cert.pem +35 -0
  44. data/spec/certificates/pk.pem +51 -0
  45. data/spec/spec_helper.rb +9 -0
  46. metadata +143 -0
@@ -0,0 +1,219 @@
1
+ # Copyright (c) 2009 Dan Kubb
2
+
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ # ---
23
+ # ---
24
+
25
+ # Some portions of blank.rb and mash.rb are verbatim copies of software
26
+ # licensed under the MIT license. That license is included below:
27
+
28
+ # Copyright (c) 2005-2008 David Heinemeier Hansson
29
+
30
+ # Permission is hereby granted, free of charge, to any person obtaining
31
+ # a copy of this software and associated documentation files (the
32
+ # "Software"), to deal in the Software without restriction, including
33
+ # without limitation the rights to use, copy, modify, merge, publish,
34
+ # distribute, sublicense, and/or sell copies of the Software, and to
35
+ # permit persons to whom the Software is furnished to do so, subject to
36
+ # the following conditions:
37
+
38
+ # The above copyright notice and this permission notice shall be
39
+ # included in all copies or substantial portions of the Software.
40
+
41
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
42
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
43
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
44
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
45
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
46
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
47
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48
+
49
+ # This class has dubious semantics and we only have it so that people can write
50
+ # params[:key] instead of params['key'].
51
+ class Mash < Hash
52
+
53
+ # @param constructor<Object>
54
+ # The default value for the mash. Defaults to an empty hash.
55
+ #
56
+ # [Alternatives]
57
+ # If constructor is a Hash, a new mash will be created based on the keys of
58
+ # the hash and no default value will be set.
59
+ def initialize(constructor = {})
60
+ if constructor.is_a?(Hash)
61
+ super()
62
+ update(constructor)
63
+ else
64
+ super(constructor)
65
+ end
66
+ end
67
+
68
+ # @param orig<Object> Mash being copied
69
+ #
70
+ # @return [Object] A new copied Mash
71
+ def initialize_copy(orig)
72
+ super
73
+ # Handle nested values
74
+ each do |k,v|
75
+ if v.kind_of?(Mash) || v.is_a?(Array)
76
+ self[k] = v.dup
77
+ end
78
+ end
79
+ self
80
+ end
81
+
82
+ # @param key<Object> The default value for the mash. Defaults to nil.
83
+ #
84
+ # [Alternatives]
85
+ # If key is a Symbol and it is a key in the mash, then the default value will
86
+ # be set to the value matching the key.
87
+ def default(key = nil)
88
+ if key.is_a?(Symbol) && include?(key = key.to_s)
89
+ self[key]
90
+ else
91
+ super
92
+ end
93
+ end
94
+
95
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
96
+ alias_method :regular_update, :update unless method_defined?(:regular_update)
97
+
98
+ # @param key<Object> The key to set.
99
+ # @param value<Object>
100
+ # The value to set the key to.
101
+ #
102
+ # @see Mash#convert_key
103
+ # @see Mash#convert_value
104
+ def []=(key, value)
105
+ regular_writer(convert_key(key), convert_value(value))
106
+ end
107
+
108
+ # @param other_hash<Hash>
109
+ # A hash to update values in the mash with. The keys and the values will be
110
+ # converted to Mash format.
111
+ #
112
+ # @return [Mash] The updated mash.
113
+ def update(other_hash)
114
+ other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
115
+ self
116
+ end
117
+
118
+ alias_method :merge!, :update
119
+
120
+ # @param key<Object> The key to check for. This will be run through convert_key.
121
+ #
122
+ # @return [Boolean] True if the key exists in the mash.
123
+ def key?(key)
124
+ super(convert_key(key))
125
+ end
126
+
127
+ # def include? def has_key? def member?
128
+ alias_method :include?, :key?
129
+ alias_method :has_key?, :key?
130
+ alias_method :member?, :key?
131
+
132
+ # @param key<Object> The key to fetch. This will be run through convert_key.
133
+ # @param extras<Array> Default value.
134
+ #
135
+ # @return [Object] The value at key or the default value.
136
+ def fetch(key, *extras)
137
+ super(convert_key(key), *extras)
138
+ end
139
+
140
+ # @param indices<Array>
141
+ # The keys to retrieve values for. These will be run through +convert_key+.
142
+ #
143
+ # @return [Array] The values at each of the provided keys
144
+ def values_at(*indices)
145
+ indices.collect {|key| self[convert_key(key)]}
146
+ end
147
+
148
+ # @param hash<Hash> The hash to merge with the mash.
149
+ #
150
+ # @return [Mash] A new mash with the hash values merged in.
151
+ def merge(hash)
152
+ self.dup.update(hash)
153
+ end
154
+
155
+ # @param key<Object>
156
+ # The key to delete from the mash.\
157
+ def delete(key)
158
+ super(convert_key(key))
159
+ end
160
+
161
+ # @return [Mash] A new mash without the selected keys.
162
+ #
163
+ # @example
164
+ # { :one => 1, :two => 2, :three => 3 }.except(:one)
165
+ # #=> { "two" => 2, "three" => 3 }
166
+ def except(*keys)
167
+ super(*keys.map {|k| convert_key(k)})
168
+ end
169
+
170
+ # Used to provide the same interface as Hash.
171
+ #
172
+ # @return [Mash] This mash unchanged.
173
+ def stringify_keys!; self end
174
+
175
+ # @return [Hash] The mash as a Hash with symbolized keys.
176
+ def symbolize_keys
177
+ h = Hash.new(default)
178
+ each { |key, val| h[key.to_sym] = val }
179
+ h
180
+ end
181
+
182
+ # @return [Hash] The mash as a Hash with string keys.
183
+ def to_hash
184
+ Hash.new(default).merge(self)
185
+ end
186
+
187
+ # @return [Mash] Convert a Hash into a Mash
188
+ # The input Hash's default value is maintained
189
+ def self.from_hash(hash)
190
+ mash = Mash.new(hash)
191
+ mash.default = hash.default
192
+ mash
193
+ end
194
+
195
+ protected
196
+ # @param key<Object> The key to convert.
197
+ #
198
+ # @api private
199
+ def convert_key(key)
200
+ key.kind_of?(Symbol) ? key.to_s : key
201
+ end
202
+
203
+ # @param value<Object> The value to convert.
204
+ #
205
+ # @return [Object]
206
+ # The converted value. A Hash or an Array of hashes, will be converted to
207
+ # their Mash equivalents.
208
+ #
209
+ # @api private
210
+ def convert_value(value)
211
+ if value.class == Hash
212
+ Mash.from_hash(value)
213
+ elsif value.is_a?(Array)
214
+ value.collect { |e| convert_value(e) }
215
+ else
216
+ value
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,42 @@
1
+ module PuppetRestClient::PE
2
+ extend PuppetRestClient::PE::Config
3
+
4
+ class << self
5
+ # Convenience alias for PuppetRestClient::DbConnection.new
6
+ #
7
+ # return [PuppetRestClient::DbConnection]
8
+ def new(options=Mash.new)
9
+ PuppetRestClient::PE::Connection.new(options)
10
+ end
11
+
12
+ # Delegate methods to PuppetRestClient::Connection
13
+ def method_missing(method, *args, &block)
14
+ return super unless new.respond_to?(method)
15
+ new.send(method, *args, &block)
16
+ end
17
+
18
+ def respond_to?(method, include_private=false)
19
+ new.respond_to?(method, include_private) || super(method, include_private)
20
+ end
21
+
22
+ def read_key_file(path)
23
+ key_file_path = File.expand_path(path)
24
+
25
+ begin
26
+ raw_key = File.read(key_file_path).strip
27
+ rescue SystemCallError, IOError => e
28
+ raise IOError, "Unable to read #{key_file_path}"
29
+ end
30
+
31
+ begin_rsa = '-----BEGIN RSA PRIVATE KEY-----'
32
+ end_rsa = '-----END RSA PRIVATE KEY-----'
33
+
34
+ unless (raw_key =~ /\A#{begin_rsa}$/) && (raw_key =~ /^#{end_rsa}\Z/)
35
+ msg = "The file #{key_file_path} is not a properly formatted private key.\n"
36
+ msg << "It must contain '#{begin_rsa}' and '#{end_rsa}'"
37
+ raise ArgumentError, msg
38
+ end
39
+ return OpenSSL::PKey::RSA.new(raw_key)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,93 @@
1
+ module PuppetRestClient::PE
2
+ module Config
3
+
4
+ # The default Chef server URL
5
+ DEFAULT_SERVER_URL = 'http://localhost:8140'
6
+
7
+ # The default Spice User-Agent header
8
+ DEFAULT_USER_AGENT = "PuppetRestClient #{PuppetRestClient::VERSION}"
9
+
10
+ # Default connection options
11
+ DEFAULT_CONNECTION_OPTIONS = {}
12
+
13
+ # Default client name
14
+ DEFAULT_CLIENT_NAME = ''
15
+
16
+ # Default key file
17
+ DEFAULT_CLIENT_KEY = ''
18
+
19
+ DEFAULT_ENVIRONMENT = 'production'
20
+
21
+ DEFAULT_ACCEPT = 'pson'
22
+
23
+ # Default puppetpe rest api version
24
+ # v1, v2 leave blank
25
+ # 2015.2 or greater pass in 'puppet/v3'
26
+ DEFAULT_API_VERSION = nil
27
+
28
+ # An array of valid config options
29
+ VALID_OPTIONS_KEYS = [
30
+ :server_url,
31
+ :environment,
32
+ :api_version,
33
+ :client_name,
34
+ :client_key,
35
+ :user_agent,
36
+ :connection_options,
37
+ :middleware,
38
+ :accept
39
+ ]
40
+
41
+ # Default middleware stack
42
+ DEFAULT_MIDDLEWARE = Proc.new do |builder|
43
+ builder.use PuppetRestClient::Response::ParseJSON
44
+ builder.use PuppetRestClient::Response::ClientError
45
+ builder.adapter Faraday.default_adapter
46
+ end
47
+
48
+ VALID_OPTIONS_KEYS.each do |key|
49
+ attr_accessor key
50
+ end
51
+
52
+ # Reset all config options to default when the module is extended
53
+ def self.extended(base)
54
+ base.reset
55
+ end # def self.extended
56
+
57
+ # Convenience method to configure PuppetRestClient in a block
58
+ # @example Configuring PuppetRestClient
59
+ # PuppetRestClient.setup do |s|
60
+ # s.server_url = "http://puppetdb.example.com:8081"
61
+ # s.client_name = "admin"
62
+ # s.client_key = PuppetRestClient.read_key_file("/path/to/key_file.pem")
63
+ # end
64
+ # @yieldparam PuppetRestClient
65
+ # @yieldreturn PuppetRestClient
66
+ def setup
67
+ yield self
68
+ self
69
+ end
70
+
71
+ # Create an options hash from valid options keys
72
+ def options
73
+ options = {}
74
+ VALID_OPTIONS_KEYS.each{|k| options[k] = send(k)}
75
+ options
76
+ end
77
+
78
+ # Reset all config options to their defaults
79
+ def reset
80
+ self.user_agent = DEFAULT_USER_AGENT
81
+ self.environment = DEFAULT_ENVIRONMENT
82
+ self.api_version = DEFAULT_API_VERSION
83
+ self.server_url = DEFAULT_SERVER_URL
84
+ self.client_name = DEFAULT_CLIENT_NAME
85
+ self.client_key = DEFAULT_CLIENT_KEY
86
+ self.connection_options = DEFAULT_CONNECTION_OPTIONS
87
+ self.middleware = DEFAULT_MIDDLEWARE
88
+ self.accept = DEFAULT_ACCEPT
89
+ self
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,25 @@
1
+ module PuppetRestClient::PE
2
+ class Connection
3
+ include PuppetRestClient::PE::Connection::Node
4
+ include PuppetRestClient::PE::Connection::Catalog
5
+ include PuppetRestClient::PE::Connection::CaCert
6
+ include PuppetRestClient::PE::Request
7
+
8
+ Config::VALID_OPTIONS_KEYS.each do |key|
9
+ attr_accessor key
10
+ end
11
+
12
+ def initialize(attrs=Mash.new)
13
+ attrs = PuppetRestClient::PE.options.merge(attrs)
14
+
15
+ #unless attrs[:client_key].is_a?(OpenSSL::PKey::RSA)
16
+ # attrs[:client_key] = OpenSSL::PKey::RSA.new(attrs[:client_key])
17
+ #end
18
+
19
+ PuppetRestClient::PE::Config::VALID_OPTIONS_KEYS.each do |key|
20
+ instance_variable_set("@#{key}".to_sym, attrs[key])
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ module PuppetRestClient::PE
2
+ class Connection
3
+ module CaCert
4
+ def ca_cert
5
+ self.accept = 's'
6
+ get(api_path('certificate', 'ca'), nil, {:raw => 1}).body.strip
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module PuppetRestClient::PE
2
+ class Connection
3
+ module Catalog
4
+ def catalog(name)
5
+ attributes = get(api_path('catalog', name))
6
+ PuppetRestClient::PE::Catalog.get_or_new(attributes)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module PuppetRestClient::PE
2
+ class Connection
3
+ module Node
4
+ def node(name)
5
+ attributes = get(api_path('node', name))
6
+ PuppetRestClient::PE::Node.get_or_new(attributes)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,100 @@
1
+ module PuppetRestClient::PE
2
+ class Base
3
+ attr_accessor :attrs
4
+ alias :to_hash :attrs
5
+
6
+ @@identity_map = PuppetRestClient::IdentityMap.new
7
+
8
+ def self.identity_map
9
+ @@identity_map
10
+ end # def self.identity_map
11
+
12
+ # Define methods that retrieve the value from an initialized instance variable Hash, using the attribute as a key
13
+ #
14
+ # @overload self.attr_reader(attr)
15
+ # @param attr [Symbol]
16
+ # @overload self.attr_reader(attrs)
17
+ # @param attrs [Array<Symbol>]
18
+ def self.attr_reader(*attrs)
19
+ attrs.each do |attribute|
20
+ class_eval do
21
+ define_method attribute do
22
+ @attrs[attribute.to_s]
23
+ end
24
+ define_method "#{attribute}=" do |value|
25
+ @attrs[attribute.to_s] = value
26
+ end
27
+ end
28
+ end
29
+ end # def self.attr_reader
30
+
31
+ def self.get(attrs=Mash.new)
32
+ @@identity_map[self] ||= {}
33
+ if attrs['title']
34
+ @@identity_map[self][attrs['title']] && @@identity_map[self][attrs['title']].update(attrs)
35
+ elsif attrs['resource']
36
+ @@identity_map[self][attrs['resource']] && @@identity_map[self][attrs['resource']].update(attrs)
37
+ else
38
+ @@identity_map[self][Marshal.dump(attrs)]
39
+ end
40
+ end # def self.get
41
+
42
+ # Retrieve an object from the identity map or initialize a new object
43
+ def self.get_or_new(attrs=Mash.new)
44
+ self.get(attrs) || self.new(attrs)
45
+ end # def self.get_or_new
46
+
47
+ # Initializes a new object
48
+ #
49
+ # @param attrs [Hash]
50
+ # @return [PuppetRestClient::Base]
51
+ def initialize(attrs=Mash.new)
52
+ self.class.attr_reader *attrs.keys
53
+ attrs.stringify_keys!
54
+ self.update attrs
55
+ if attrs['title']
56
+ @@identity_map[self.class] ||= {}
57
+ @@identity_map[self.class][attrs['title']] = self
58
+ elsif attrs['resource']
59
+ @@identity_map[self.class] ||= {}
60
+ @@identity_map[self.class][attrs['resource']] = self
61
+ else
62
+ @@identity_map[self.class] ||= {}
63
+ @@identity_map[self.class][Marshal.dump(attrs)] = self
64
+ end
65
+ end # def initialize
66
+
67
+ # Fetches an attribute of an object using hash notation
68
+ #
69
+ # @param method [String, Symbol] Message to send to the object
70
+ def [](method)
71
+ self.__send__(method.to_sym)
72
+ rescue NoMethodError
73
+ nil
74
+ end # def []
75
+
76
+ # Update the attributes of an object
77
+ #
78
+ # @param attrs [Hash]
79
+ # @return [PuppetRestClient::Base]
80
+ def update(attrs)
81
+ @attrs = attrs
82
+ self
83
+ end # def update
84
+
85
+ # @return [String]
86
+ def resource
87
+ @attrs['resource']
88
+ end # def id
89
+
90
+ # @return [String]
91
+ def title
92
+ @attrs['title']
93
+ end # def name
94
+
95
+ def keys
96
+ @attrs.keys
97
+ end # def keys
98
+
99
+ end
100
+ end