puppet-rest 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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