chef-sugar-ng 4.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.github/lock.yml +3 -0
  3. data/.github/reaction.yml +1 -0
  4. data/.gitignore +26 -0
  5. data/.kitchen.yml +16 -0
  6. data/.travis.yml +17 -0
  7. data/CHANGELOG.md +261 -0
  8. data/CONTRIBUTING.md +20 -0
  9. data/Gemfile +2 -0
  10. data/LICENSE +201 -0
  11. data/README.md +540 -0
  12. data/Rakefile +11 -0
  13. data/chef-sugar-ng.gemspec +33 -0
  14. data/lib/chef/sugar.rb +51 -0
  15. data/lib/chef/sugar/architecture.rb +171 -0
  16. data/lib/chef/sugar/cloud.rb +192 -0
  17. data/lib/chef/sugar/constraints.rb +108 -0
  18. data/lib/chef/sugar/constraints_dsl.rb +83 -0
  19. data/lib/chef/sugar/core_extensions.rb +19 -0
  20. data/lib/chef/sugar/core_extensions/array.rb +34 -0
  21. data/lib/chef/sugar/core_extensions/object.rb +27 -0
  22. data/lib/chef/sugar/core_extensions/string.rb +66 -0
  23. data/lib/chef/sugar/data_bag.rb +146 -0
  24. data/lib/chef/sugar/docker.rb +40 -0
  25. data/lib/chef/sugar/filters.rb +227 -0
  26. data/lib/chef/sugar/init.rb +62 -0
  27. data/lib/chef/sugar/ip.rb +48 -0
  28. data/lib/chef/sugar/kernel.rb +49 -0
  29. data/lib/chef/sugar/kitchen.rb +40 -0
  30. data/lib/chef/sugar/node.rb +213 -0
  31. data/lib/chef/sugar/platform.rb +327 -0
  32. data/lib/chef/sugar/platform_family.rb +179 -0
  33. data/lib/chef/sugar/ruby.rb +51 -0
  34. data/lib/chef/sugar/run_context.rb +41 -0
  35. data/lib/chef/sugar/shell.rb +147 -0
  36. data/lib/chef/sugar/vagrant.rb +77 -0
  37. data/lib/chef/sugar/version.rb +21 -0
  38. data/lib/chef/sugar/virtualization.rb +151 -0
  39. data/libraries/chef-sugar.rb +1 -0
  40. data/metadata.rb +24 -0
  41. data/recipes/default.rb +20 -0
  42. data/spec/spec_helper.rb +25 -0
  43. data/spec/support/shared_examples.rb +20 -0
  44. data/spec/unit/chef/sugar/architecture_spec.rb +129 -0
  45. data/spec/unit/chef/sugar/cloud_spec.rb +149 -0
  46. data/spec/unit/chef/sugar/constraints_spec.rb +45 -0
  47. data/spec/unit/chef/sugar/core_extensions/array_spec.rb +10 -0
  48. data/spec/unit/chef/sugar/core_extensions/object_spec.rb +62 -0
  49. data/spec/unit/chef/sugar/core_extensions/string_spec.rb +48 -0
  50. data/spec/unit/chef/sugar/data_bag_spec.rb +118 -0
  51. data/spec/unit/chef/sugar/docker_spec.rb +39 -0
  52. data/spec/unit/chef/sugar/init_spec.rb +74 -0
  53. data/spec/unit/chef/sugar/ip_spec.rb +53 -0
  54. data/spec/unit/chef/sugar/kernel_spec.rb +16 -0
  55. data/spec/unit/chef/sugar/kitchen_spec.rb +18 -0
  56. data/spec/unit/chef/sugar/node_spec.rb +172 -0
  57. data/spec/unit/chef/sugar/platform_family_spec.rb +166 -0
  58. data/spec/unit/chef/sugar/platform_spec.rb +342 -0
  59. data/spec/unit/chef/sugar/ruby_spec.rb +39 -0
  60. data/spec/unit/chef/sugar/run_context_spec.rb +19 -0
  61. data/spec/unit/chef/sugar/shell_spec.rb +104 -0
  62. data/spec/unit/chef/sugar/vagrant_spec.rb +37 -0
  63. data/spec/unit/chef/sugar/virtualization_spec.rb +135 -0
  64. data/spec/unit/recipes/default_spec.rb +9 -0
  65. metadata +202 -0
@@ -0,0 +1,213 @@
1
+ #
2
+ # Copyright 2013-2015, Seth Vargo <sethvargo@gmail.com>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ class Chef
18
+ class Node
19
+ class AttributeDoesNotExistError < StandardError
20
+ def initialize(keys, key)
21
+ hash = keys.map { |key| "['#{key}']" }
22
+
23
+ super <<-EOH
24
+ No attribute `node#{hash.join}' exists on
25
+ the current node. Specifically the `#{key}' attribute is not
26
+ defined. Please make sure you have spelled everything correctly.
27
+ EOH
28
+ end
29
+ end
30
+ #
31
+ # Determine if the current node is in the given Chef environment
32
+ # (or matches the given regular expression).
33
+ #
34
+ # @param [String, Regex] environment
35
+ #
36
+ # @return [Boolean]
37
+ #
38
+ def in?(environment)
39
+ environment === chef_environment
40
+ end
41
+
42
+ #
43
+ # Safely fetch a deeply nested attribute by specifying a list of keys,
44
+ # bypassing Ruby's Hash notation. This method swallows +NoMethodError+
45
+ # exceptions, avoiding the most common error in Chef-land.
46
+ #
47
+ # This method will return +nil+ if any deeply nested key does not exist.
48
+ #
49
+ # @see [Node#deep_fetch!]
50
+ #
51
+ def deep_fetch(*keys)
52
+ deep_fetch!(*keys)
53
+ rescue NoMethodError, AttributeDoesNotExistError
54
+ nil
55
+ end
56
+
57
+ #
58
+ # Deeply fetch a node attribute by specifying a list of keys, bypassing
59
+ # Ruby's Hash notation.
60
+ #
61
+ # This method will raise any exceptions, such as
62
+ # +undefined method `[]' for nil:NilClass+, just as if you used the native
63
+ # attribute notation. If you want a safely vivified hash, see {deep_fetch}.
64
+ #
65
+ # @example Fetch a deeply nested key
66
+ # node.deep_fetch(:foo, :bar, :zip) #=> node['foo']['bar']['zip']
67
+ #
68
+ # @param [Array<String, Symbol>] keys
69
+ # the list of keys to kdeep fetch
70
+ #
71
+ # @return [Object]
72
+ #
73
+ def deep_fetch!(*keys)
74
+ keys.map!(&:to_s)
75
+
76
+ keys.inject(attributes.to_hash) do |hash, key|
77
+ if hash.key?(key)
78
+ hash[key]
79
+ else
80
+ raise AttributeDoesNotExistError.new(keys, key)
81
+ end
82
+ end
83
+ end
84
+
85
+ #
86
+ # Dynamically define the current namespace. Multiple namespaces may be
87
+ # nested.
88
+ #
89
+ # @example Define a simple namespace
90
+ #
91
+ # namespace 'apache2' do
92
+ # # ...
93
+ # end
94
+ #
95
+ # @example Define a nested namespace
96
+ #
97
+ # namespace 'apache2', 'config' do
98
+ # # ...
99
+ # end
100
+ #
101
+ # @example Define a complex nested namespace
102
+ #
103
+ # namespace 'apache2' do
104
+ # namespace 'config' do
105
+ # # ...
106
+ # end
107
+ # end
108
+ #
109
+ # @example Define a namespace with a custom precedence level
110
+ #
111
+ # namespace 'apache2', precedence: normal do
112
+ # # Attributes here will use the "normal" level
113
+ # end
114
+ #
115
+ # @example Define different nested precedence levels
116
+ #
117
+ # namespace 'apache2', precedence: normal do
118
+ # # Attributes defined here will use the "normal" level
119
+ #
120
+ # namespace 'config', precedence: override do
121
+ # # Attributes defined here will use the "override" level
122
+ # end
123
+ # end
124
+ #
125
+ #
126
+ # @param [Array] args
127
+ # the list of arguments (such as the namespace and precedence levels)
128
+ # the user gave
129
+ # @param [Proc] block
130
+ # the nested evaluation context
131
+ #
132
+ # @return [nil]
133
+ # to prevent accidential method chaining if the block isn't closed
134
+ #
135
+ def namespace(*args, &block)
136
+ @namespace_options = namespace_options.merge(args.last.is_a?(Hash) ? args.pop : {})
137
+
138
+ keys = args.map(&:to_s)
139
+
140
+ @current_namespace = current_namespace + keys
141
+ instance_eval(&block)
142
+ @current_namespace = current_namespace - keys
143
+
144
+ if @current_namespace.empty?
145
+ @namespace_options = nil
146
+ end
147
+ nil
148
+ end
149
+
150
+ alias_method :old_method_missing, :method_missing
151
+ #
152
+ # Provide a nice DSL for defining attributes. +method_missing+ is called
153
+ # on all the attribute names. For more information on how to use the DSL,
154
+ # see the class-level documentation.
155
+ #
156
+ # @return [nil]
157
+ # to prevent accidential method chaining if the block isn't closed
158
+ # @return [Object]
159
+ # If no argument is passed in, method becomes an attribute accessor
160
+ #
161
+ def method_missing(m, *args, &block)
162
+ old_method_missing(m, *args, &block)
163
+ rescue NoMethodError
164
+ # The Node Attribute's key is the method name
165
+ key = m.to_s
166
+ # If arguments are passed in, set node attribute with args as the value
167
+ if args.size > 0
168
+ vivified[key] = args.size == 1 ? args.first : args
169
+ return nil
170
+ # If no arguments are passed in, attempt to access corresponding attribute
171
+ else
172
+ deep_key = current_namespace.dup << key
173
+ return deep_fetch!(*deep_key)
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ #
180
+ # The namespace options.
181
+ #
182
+ # @return [Hash]
183
+ #
184
+ def namespace_options
185
+ @namespace_options ||= {
186
+ precedence: default
187
+ }
188
+ end
189
+
190
+ #
191
+ # The current namespace. This is actually a reverse-ordered array that
192
+ # vivifies the correct hash.#
193
+ #
194
+ # @return [Array<String>]
195
+ #
196
+ def current_namespace
197
+ @current_namespace ||= []
198
+ end
199
+
200
+ #
201
+ # The vivified (fake-filled) hash. It is assumed that the default value
202
+ # for non-existent keys in the hash is a new, empty hash.
203
+ #
204
+ # @return [Hash<String, Hash>]
205
+ #
206
+ def vivified
207
+ current_namespace.inject(namespace_options[:precedence]) do |hash, item|
208
+ hash[item] ||= {}
209
+ hash[item]
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,327 @@
1
+ #
2
+ # Copyright 2013-2015, Seth Vargo <sethvargo@gmail.com>
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require_relative 'constraints'
18
+
19
+ class Chef
20
+ module Sugar
21
+ module Platform
22
+ extend self
23
+
24
+ PLATFORM_VERSIONS = {
25
+ 'debian' => {
26
+ 'squeeze' => '6',
27
+ 'wheezy' => '7',
28
+ 'jessie' => '8',
29
+ 'stretch' => '9',
30
+ 'buster' => '10',
31
+ },
32
+ 'linuxmint' => {
33
+ 'tara' => '19',
34
+ 'sarah' => '18',
35
+ 'qiana' => '17',
36
+ 'petra' => '16',
37
+ 'olivia' => '15',
38
+ 'nadia' => '14',
39
+ 'maya' => '13',
40
+ 'lisa' => '12',
41
+ },
42
+ 'mac_os_x' => {
43
+ 'lion' => '10.7',
44
+ 'mountain_lion' => '10.8',
45
+ 'mavericks' => '10.9',
46
+ 'yosemite' => '10.10',
47
+ 'el_capitan' => '10.11',
48
+ 'sierra' => '10.12',
49
+ 'high_sierra' => '10.13',
50
+ 'mojave' => '10.14',
51
+ },
52
+ 'redhat' => {
53
+ 'santiago' => '6',
54
+ '6' => '6',
55
+ 'maipo' => '7',
56
+ '7' => '7',
57
+ 'oompa' => '8',
58
+ '8' => '8'
59
+ },
60
+ 'centos' => {
61
+ 'final' => '6',
62
+ '6' => '6',
63
+ 'core' => '7',
64
+ '7' => '7'
65
+ },
66
+ 'solaris' => {
67
+ '7' => '5.7',
68
+ '8' => '5.8',
69
+ '9' => '5.9',
70
+ '10' => '5.10',
71
+ '11' => '5.11',
72
+ },
73
+ 'ubuntu' => {
74
+ 'lucid' => '10.04',
75
+ 'maverick' => '10.10',
76
+ 'natty' => '11.04',
77
+ 'oneiric' => '11.10',
78
+ 'precise' => '12.04',
79
+ 'quantal' => '12.10',
80
+ 'raring' => '13.04',
81
+ 'saucy' => '13.10',
82
+ 'trusty' => '14.04',
83
+ 'utopic' => '14.10',
84
+ 'vivid' => '15.04',
85
+ 'wily' => '15.10',
86
+ 'xenial' => '16.04',
87
+ 'zesty' => '17.04',
88
+ 'artful' => '17.10',
89
+ 'bionic' => '18.04',
90
+ 'cosmic' => '18.10',
91
+ },
92
+ }
93
+
94
+ COMPARISON_OPERATORS = {
95
+ 'after' => ->(a, b) { a > b },
96
+ 'after_or_at' => ->(a, b) { a >= b },
97
+ '' => ->(a, b) { a == b },
98
+ 'before' => ->(a, b) { a < b },
99
+ 'before_or_at' => ->(a, b) { a <= b },
100
+ }
101
+
102
+ # Dynamically define custom matchers at runtime in a matrix. For each
103
+ # Platform, we create a map of named versions to their numerical
104
+ # equivalents (e.g. debian_before_squeeze?).
105
+ PLATFORM_VERSIONS.each do |platform, versions|
106
+ versions.each do |name, version|
107
+ COMPARISON_OPERATORS.each do |operator, block|
108
+ method_name = "#{platform}_#{operator}_#{name}?".squeeze('_').to_sym
109
+ define_method(method_name) do |node|
110
+ # Find the highest precedence that we actually care about based
111
+ # off of what was given to us in the list.
112
+ length = version.split('.').size
113
+ check = node['platform_version'].split('.')[0...length].join('.')
114
+
115
+ # Calling #to_f will ensure we only check major versions since
116
+ # '10.04.4'.to_f #=> 10.04. We also use a regex to match on
117
+ # platform so things like `solaris2` match on `solaris`.
118
+ node['platform'] =~ %r(^#{platform}) && block.call(check.to_f, version.to_f)
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ #
125
+ # Determine if the current node is linux mint.
126
+ #
127
+ # @param [Chef::Node] node
128
+ #
129
+ # @return [Boolean]
130
+ #
131
+ def linux_mint?(node)
132
+ node['platform'] == 'linuxmint'
133
+ end
134
+ alias_method :mint?, :linux_mint?
135
+
136
+ #
137
+ # Determine if the current node is ubuntu.
138
+ #
139
+ # @param [Chef::Node] node
140
+ #
141
+ # @return [Boolean]
142
+ #
143
+ def ubuntu?(node)
144
+ node['platform'] == 'ubuntu'
145
+ end
146
+
147
+ #
148
+ # Determine if the current node is debian (platform, not platform_family).
149
+ #
150
+ # @param [Chef::Node] node
151
+ #
152
+ # @return [Boolean]
153
+ #
154
+ def debian_platform?(node)
155
+ node['platform'] == 'debian'
156
+ end
157
+
158
+ #
159
+ # Determine if the current node is amazon linux.
160
+ #
161
+ # @param [Chef::Node] node
162
+ #
163
+ # @return [Boolean]
164
+ #
165
+ def amazon_linux?(node)
166
+ node['platform'] == 'amazon'
167
+ end
168
+ alias_method :amazon?, :amazon_linux?
169
+
170
+ #
171
+ # Determine if the current node is centos.
172
+ #
173
+ # @param [Chef::Node] node
174
+ #
175
+ # @return [Boolean]
176
+ #
177
+ def centos?(node)
178
+ node['platform'] == 'centos'
179
+ end
180
+
181
+ #
182
+ # Determine if the current node is oracle linux.
183
+ #
184
+ # @param [Chef::Node] node
185
+ #
186
+ # @return [Boolean]
187
+ #
188
+ def oracle_linux?(node)
189
+ node['platform'] == 'oracle'
190
+ end
191
+ alias_method :oracle?, :oracle_linux?
192
+
193
+ #
194
+ # Determine if the current node is scientific linux.
195
+ #
196
+ # @param [Chef::Node] node
197
+ #
198
+ # @return [Boolean]
199
+ #
200
+ def scientific_linux?(node)
201
+ node['platform'] == 'scientific'
202
+ end
203
+ alias_method :scientific?, :scientific_linux?
204
+
205
+ #
206
+ # Determine if the current node is redhat enterprise.
207
+ #
208
+ # @param [Chef::Node] node
209
+ #
210
+ # @return [Boolean]
211
+ #
212
+ def redhat_enterprise_linux?(node)
213
+ node['platform'] == 'redhat'
214
+ end
215
+ alias_method :redhat_enterprise?, :redhat_enterprise_linux?
216
+
217
+ #
218
+ # Determine if the current node is fedora (platform, not platform_family).
219
+ #
220
+ # @param [Chef::Node] node
221
+ #
222
+ # @return [Boolean]
223
+ #
224
+ def fedora_platform?(node)
225
+ node['platform'] == 'fedora'
226
+ end
227
+
228
+ #
229
+ # Determine if the current node is solaris2
230
+ #
231
+ # @param [Chef::Node] node
232
+ #
233
+ # @return [Boolean]
234
+ #
235
+ def solaris2?(node)
236
+ node['platform'] == 'solaris2'
237
+ end
238
+ alias_method :solaris?, :solaris2?
239
+
240
+ #
241
+ # Determine if the current node is aix
242
+ #
243
+ # @param [Chef::Node] node
244
+ #
245
+ # @return [Boolean]
246
+ #
247
+ def aix?(node)
248
+ node['platform'] == 'aix'
249
+ end
250
+
251
+ #
252
+ # Determine if the current node is smartos
253
+ #
254
+ # @param [Chef::Node] node
255
+ #
256
+ # @return [Boolean]
257
+ #
258
+ def smartos?(node)
259
+ node['platform'] == 'smartos'
260
+ end
261
+
262
+ #
263
+ # Determine if the current node is omnios
264
+ #
265
+ # @param [Chef::Node] node
266
+ #
267
+ # @return [Boolean]
268
+ #
269
+ def omnios?(node)
270
+ node['platform'] == 'omnios'
271
+ end
272
+
273
+ #
274
+ # Determine if the current node is raspbian
275
+ #
276
+ # @param [Chef::Node] node
277
+ #
278
+ # @return [Boolean]
279
+ #
280
+ def raspbian?(node)
281
+ node['platform'] == 'raspbian'
282
+ end
283
+
284
+ #
285
+ # Determine if the current node is a Cisco nexus device
286
+ #
287
+ # @param [Chef::Node] node
288
+ #
289
+ # @return [Boolean]
290
+ #
291
+ def nexus?(node)
292
+ node['platform'] == 'nexus'
293
+ end
294
+
295
+ #
296
+ # Determine if the current node is a Cisco IOS-XR device
297
+ #
298
+ # @param [Chef::Node] node
299
+ #
300
+ # @return [Boolean]
301
+ #
302
+ def ios_xr?(node)
303
+ node['platform'] == 'ios_xr'
304
+ end
305
+
306
+ #
307
+ # Return the platform_version for the node. Acts like a String
308
+ # but also provides a mechanism for checking version constraints.
309
+ #
310
+ # @param [Chef::Node] node
311
+ #
312
+ # @return [Chef::Sugar::Constraints::Version]
313
+ #
314
+ def platform_version(node)
315
+ Chef::Sugar::Constraints::Version.new(node['platform_version'])
316
+ end
317
+ end
318
+
319
+ module DSL
320
+ Chef::Sugar::Platform.instance_methods.each do |name|
321
+ define_method(name) do
322
+ Chef::Sugar::Platform.send(name, node)
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end