chef-sugar-ng 4.2.2

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 (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