chef-utils 16.11.7 → 17.2.29
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.
- checksums.yaml +4 -4
- data/chef-utils.gemspec +5 -1
- data/lib/chef-utils/dist.rb +44 -0
- data/lib/chef-utils/dsl/cloud.rb +21 -10
- data/lib/chef-utils/dsl/introspection.rb +11 -0
- data/lib/chef-utils/dsl/platform.rb +15 -0
- data/lib/chef-utils/dsl/windows.rb +1 -1
- data/lib/chef-utils/internal.rb +1 -1
- data/lib/chef-utils/mash.rb +15 -0
- data/lib/chef-utils/parallel_map.rb +131 -0
- data/lib/chef-utils/version.rb +1 -1
- data/spec/unit/dsl/cloud_spec.rb +4 -0
- data/spec/unit/dsl/introspection_spec.rb +12 -0
- data/spec/unit/dsl/platform_family_spec.rb +7 -7
- data/spec/unit/dsl/platform_spec.rb +14 -0
- data/spec/unit/parallel_map_spec.rb +156 -0
- metadata +21 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 860b9ebe97ac8f22fcdeebb27bf112b4535edcffbb189dc7543ab4c30a1542cb
|
|
4
|
+
data.tar.gz: 7a3e2aab7feb50f45f4a57679d5644a8a4beab2b96eeaaf86032c2bdf6392aca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5c749b979ec103b8f2b052cf2054747adc4e837f69251269412e37f2af6b90c3007dd41c94622de06d40d76964eb0f56d975d02d9965b22117a66e629ba8075d
|
|
7
|
+
data.tar.gz: be28ce9afeead797ba7783a8e60635061589c1e5b4343b76f8e927d1d82e25d04da7bd0910728270839259c45e7a0292b0a6e0cc481093aa4d7d14528f7f6465
|
data/chef-utils.gemspec
CHANGED
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.homepage = "https://github.com/chef/chef/tree/master/chef-utils"
|
|
14
14
|
spec.license = "Apache-2.0"
|
|
15
15
|
|
|
16
|
-
spec.required_ruby_version = ">= 2.6
|
|
16
|
+
spec.required_ruby_version = ">= 2.6"
|
|
17
17
|
|
|
18
18
|
spec.metadata = {
|
|
19
19
|
"bug_tracker_uri" => "https://github.com/chef/chef/issues",
|
|
@@ -41,6 +41,10 @@ Gem::Specification.new do |spec|
|
|
|
41
41
|
# ABSOLUTELY NO EXCEPTIONS
|
|
42
42
|
#
|
|
43
43
|
|
|
44
|
+
# concurrent-ruby is: 1. lightweight, 2. has zero deps, 3. is external to chef
|
|
45
|
+
# this is used for the parallel_map enumerable extension for lightweight threading
|
|
46
|
+
spec.add_dependency "concurrent-ruby"
|
|
47
|
+
|
|
44
48
|
spec.files = %w{Rakefile LICENSE} + Dir.glob("*.gemspec") +
|
|
45
49
|
Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
|
|
46
50
|
end
|
data/lib/chef-utils/dist.rb
CHANGED
|
@@ -15,6 +15,25 @@ module ChefUtils
|
|
|
15
15
|
PRODUCT = "Chef Automate"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
+
class Cli
|
|
19
|
+
# the chef-cli product name
|
|
20
|
+
PRODUCT = "Chef CLI"
|
|
21
|
+
|
|
22
|
+
# the chef-cli gem
|
|
23
|
+
GEM = "chef-cli"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Habitat
|
|
27
|
+
# name of the Habitat product
|
|
28
|
+
PRODUCT = "Chef Habitat"
|
|
29
|
+
|
|
30
|
+
# A short designation for the product
|
|
31
|
+
SHORT = "habitat"
|
|
32
|
+
|
|
33
|
+
# The hab cli binary
|
|
34
|
+
EXEC = "hab"
|
|
35
|
+
end
|
|
36
|
+
|
|
18
37
|
class Infra
|
|
19
38
|
# When referencing a product directly, like Chef (Now Chef Infra)
|
|
20
39
|
PRODUCT = "Chef Infra Client"
|
|
@@ -42,6 +61,17 @@ module ChefUtils
|
|
|
42
61
|
# The suffix for Chef's /etc/chef, /var/chef and C:\\Chef directories
|
|
43
62
|
# "chef" => /etc/cinc, /var/cinc, C:\\cinc
|
|
44
63
|
DIR_SUFFIX = "chef"
|
|
64
|
+
|
|
65
|
+
# The client's gem
|
|
66
|
+
GEM = "chef"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
class Inspec
|
|
70
|
+
# The InSpec product name
|
|
71
|
+
PRODUCT = "Chef InSpec"
|
|
72
|
+
|
|
73
|
+
# The inspec binary
|
|
74
|
+
EXEC = "inspec"
|
|
45
75
|
end
|
|
46
76
|
|
|
47
77
|
class Org
|
|
@@ -63,6 +93,9 @@ module ChefUtils
|
|
|
63
93
|
|
|
64
94
|
# knife documentation page
|
|
65
95
|
KNIFE_DOCS = "https://docs.chef.io/workstation/knife/"
|
|
96
|
+
|
|
97
|
+
# the name of the overall infra product
|
|
98
|
+
PRODUCT = "Chef Infra"
|
|
66
99
|
end
|
|
67
100
|
|
|
68
101
|
class Server
|
|
@@ -87,6 +120,17 @@ module ChefUtils
|
|
|
87
120
|
EXEC = "chef-solo"
|
|
88
121
|
end
|
|
89
122
|
|
|
123
|
+
class Workstation
|
|
124
|
+
# The full marketing name of the product
|
|
125
|
+
PRODUCT = "Chef Workstation"
|
|
126
|
+
|
|
127
|
+
# The suffix for Chef Workstation's /opt/chef-workstation or C:\\opscode\chef-workstation
|
|
128
|
+
DIR_SUFFIX = "chef-workstation"
|
|
129
|
+
|
|
130
|
+
# Workstation banner/help text
|
|
131
|
+
DOCS = "https://docs.chef.io/workstation/"
|
|
132
|
+
end
|
|
133
|
+
|
|
90
134
|
class Zero
|
|
91
135
|
# chef-zero executable
|
|
92
136
|
PRODUCT = "Chef Infra Zero"
|
data/lib/chef-utils/dsl/cloud.rb
CHANGED
|
@@ -23,7 +23,7 @@ module ChefUtils
|
|
|
23
23
|
module Cloud
|
|
24
24
|
include Internal
|
|
25
25
|
|
|
26
|
-
# Determine if the current node is
|
|
26
|
+
# Determine if the current node is running in a known cloud.
|
|
27
27
|
#
|
|
28
28
|
# @param [Chef::Node] node the node to check
|
|
29
29
|
# @since 15.8
|
|
@@ -35,7 +35,18 @@ module ChefUtils
|
|
|
35
35
|
!node["cloud"].nil?
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
#
|
|
38
|
+
# Determine if the current node is running in Alibaba Cloud
|
|
39
|
+
#
|
|
40
|
+
# @param [Chef::Node] node the node to check
|
|
41
|
+
# @since 17.0
|
|
42
|
+
#
|
|
43
|
+
# @return [Boolean]
|
|
44
|
+
#
|
|
45
|
+
def alibaba?(node = __getnode)
|
|
46
|
+
node.key?("alibaba")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Determine if the current node is running in AWS EC2.
|
|
39
50
|
#
|
|
40
51
|
# @param [Chef::Node] node the node to check
|
|
41
52
|
# @since 15.8
|
|
@@ -46,7 +57,7 @@ module ChefUtils
|
|
|
46
57
|
node.key?("ec2")
|
|
47
58
|
end
|
|
48
59
|
|
|
49
|
-
#
|
|
60
|
+
# Determine if the current node running in Google Compute Engine (GCE).
|
|
50
61
|
#
|
|
51
62
|
# @param [Chef::Node] node the node to check
|
|
52
63
|
# @since 15.8
|
|
@@ -57,7 +68,7 @@ module ChefUtils
|
|
|
57
68
|
node.key?("gce")
|
|
58
69
|
end
|
|
59
70
|
|
|
60
|
-
#
|
|
71
|
+
# Determine if the current node is running in Rackspace.
|
|
61
72
|
#
|
|
62
73
|
# @param [Chef::Node] node the node to check
|
|
63
74
|
# @since 15.8
|
|
@@ -68,7 +79,7 @@ module ChefUtils
|
|
|
68
79
|
node.key?("rackspace")
|
|
69
80
|
end
|
|
70
81
|
|
|
71
|
-
#
|
|
82
|
+
# Determine if the current node is running in Eucalyptus.
|
|
72
83
|
#
|
|
73
84
|
# @param [Chef::Node] node the node to check
|
|
74
85
|
# @since 15.8
|
|
@@ -81,7 +92,7 @@ module ChefUtils
|
|
|
81
92
|
# chef-sugar backcompat method
|
|
82
93
|
alias_method :euca?, :eucalyptus?
|
|
83
94
|
|
|
84
|
-
#
|
|
95
|
+
# Determine if the current node is running in Linode.
|
|
85
96
|
#
|
|
86
97
|
# @param [Chef::Node] node the node to check
|
|
87
98
|
# @since 15.8
|
|
@@ -92,7 +103,7 @@ module ChefUtils
|
|
|
92
103
|
node.key?("linode")
|
|
93
104
|
end
|
|
94
105
|
|
|
95
|
-
#
|
|
106
|
+
# Determine if the current node is running in OpenStack.
|
|
96
107
|
#
|
|
97
108
|
# @param [Chef::Node] node the node to check
|
|
98
109
|
# @since 15.8
|
|
@@ -103,7 +114,7 @@ module ChefUtils
|
|
|
103
114
|
node.key?("openstack")
|
|
104
115
|
end
|
|
105
116
|
|
|
106
|
-
#
|
|
117
|
+
# Determine if the current node is running in Microsoft Azure.
|
|
107
118
|
#
|
|
108
119
|
# @param [Chef::Node] node the node to check
|
|
109
120
|
# @since 15.8
|
|
@@ -114,7 +125,7 @@ module ChefUtils
|
|
|
114
125
|
node.key?("azure")
|
|
115
126
|
end
|
|
116
127
|
|
|
117
|
-
#
|
|
128
|
+
# Determine if the current node is running in DigitalOcean.
|
|
118
129
|
#
|
|
119
130
|
# @param [Chef::Node] node the node to check
|
|
120
131
|
# @since 15.8
|
|
@@ -127,7 +138,7 @@ module ChefUtils
|
|
|
127
138
|
# chef-sugar backcompat method
|
|
128
139
|
alias_method :digitalocean?, :digital_ocean?
|
|
129
140
|
|
|
130
|
-
#
|
|
141
|
+
# Determine if the current node is running in SoftLayer (IBM Cloud).
|
|
131
142
|
#
|
|
132
143
|
# @param [Chef::Node] node the node to check
|
|
133
144
|
# @since 15.8
|
|
@@ -29,6 +29,17 @@ module ChefUtils
|
|
|
29
29
|
module Introspection
|
|
30
30
|
include TrainHelpers
|
|
31
31
|
|
|
32
|
+
# Determine if the node is using the Chef Effortless pattern in which the Chef Infra Client is packaged using Chef Habitat
|
|
33
|
+
#
|
|
34
|
+
# @param [Chef::Node] node the node to check
|
|
35
|
+
# @since 17.0
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
#
|
|
39
|
+
def effortless?(node = __getnode)
|
|
40
|
+
!!(node && node.read("chef_packages", "chef", "chef_effortless"))
|
|
41
|
+
end
|
|
42
|
+
|
|
32
43
|
# Determine if the node is a docker container.
|
|
33
44
|
#
|
|
34
45
|
# @param [Chef::Node] node the node to check
|
|
@@ -123,6 +123,21 @@ module ChefUtils
|
|
|
123
123
|
# chef-sugar backcompat method
|
|
124
124
|
alias_method :centos?, :centos_platform?
|
|
125
125
|
|
|
126
|
+
# Determine if the current node is CentOS Stream.
|
|
127
|
+
#
|
|
128
|
+
# @param [Chef::Node] node the node to check
|
|
129
|
+
# @since 17.0
|
|
130
|
+
#
|
|
131
|
+
# @return [Boolean]
|
|
132
|
+
#
|
|
133
|
+
def centos_stream_platform?(node = __getnode)
|
|
134
|
+
if node["os_release"]
|
|
135
|
+
node.dig("os_release", "name") == "CentOS Stream"
|
|
136
|
+
else
|
|
137
|
+
node.dig("lsb", "id") == "CentOSStream"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
126
141
|
# Determine if the current node is Oracle Linux.
|
|
127
142
|
#
|
|
128
143
|
# @param [Chef::Node] node the node to check
|
|
@@ -58,7 +58,7 @@ module ChefUtils
|
|
|
58
58
|
node["kernel"]["product_type"] == "Server"
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
-
# Determine the current Windows NT version. The NT version often differs from the marketing version, but offers a good way to find desktop and server releases that are based on the same codebase.
|
|
61
|
+
# Determine the current Windows NT version. The NT version often differs from the marketing version, but offers a good way to find desktop and server releases that are based on the same codebase. For example NT 6.3 corresponds to Windows 8.1 and Windows 2012 R2.
|
|
62
62
|
#
|
|
63
63
|
# @param [Chef::Node] node the node to check
|
|
64
64
|
# @since 15.8
|
data/lib/chef-utils/internal.rb
CHANGED
data/lib/chef-utils/mash.rb
CHANGED
|
@@ -94,6 +94,10 @@ module ChefUtils
|
|
|
94
94
|
end
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
unless method_defined?(:regular_reader)
|
|
98
|
+
alias_method :regular_reader, :[]
|
|
99
|
+
end
|
|
100
|
+
|
|
97
101
|
unless method_defined?(:regular_writer)
|
|
98
102
|
alias_method :regular_writer, :[]=
|
|
99
103
|
end
|
|
@@ -102,6 +106,11 @@ module ChefUtils
|
|
|
102
106
|
alias_method :regular_update, :update
|
|
103
107
|
end
|
|
104
108
|
|
|
109
|
+
# @param key<Object> The key to get.
|
|
110
|
+
def [](key)
|
|
111
|
+
regular_reader(key)
|
|
112
|
+
end
|
|
113
|
+
|
|
105
114
|
# @param key<Object> The key to set.
|
|
106
115
|
# @param value<Object>
|
|
107
116
|
# The value to set the key to.
|
|
@@ -112,6 +121,12 @@ module ChefUtils
|
|
|
112
121
|
regular_writer(convert_key(key), convert_value(value))
|
|
113
122
|
end
|
|
114
123
|
|
|
124
|
+
# internal API for use by Chef's deep merge cache
|
|
125
|
+
# @api private
|
|
126
|
+
def internal_get(key)
|
|
127
|
+
regular_reader(key)
|
|
128
|
+
end
|
|
129
|
+
|
|
115
130
|
# internal API for use by Chef's deep merge cache
|
|
116
131
|
# @api private
|
|
117
132
|
def internal_set(key, value)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
|
4
|
+
# License:: Apache License, Version 2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
require "concurrent/executors"
|
|
20
|
+
require "concurrent/future"
|
|
21
|
+
require "singleton" unless defined?(Singleton)
|
|
22
|
+
|
|
23
|
+
module ChefUtils
|
|
24
|
+
#
|
|
25
|
+
# This module contains ruby refinements that adds several methods to the Enumerable
|
|
26
|
+
# class which are useful for parallel processing.
|
|
27
|
+
#
|
|
28
|
+
module ParallelMap
|
|
29
|
+
refine Enumerable do
|
|
30
|
+
|
|
31
|
+
# Enumerates through the collection in parallel using the thread pool provided
|
|
32
|
+
# or the default thread pool. By using the default thread pool this supports
|
|
33
|
+
# recursively calling the method without deadlocking while using a globally
|
|
34
|
+
# fixed number of workers. This method supports lazy collections. It returns
|
|
35
|
+
# synchronously, waiting until all the work is done. Failures are only reported
|
|
36
|
+
# after the collection has executed and only the first exception is raised.
|
|
37
|
+
#
|
|
38
|
+
# (0..).lazy.parallel_map { |i| i*i }.first(5)
|
|
39
|
+
#
|
|
40
|
+
# @return [Array] output results
|
|
41
|
+
#
|
|
42
|
+
def parallel_map(pool: nil)
|
|
43
|
+
return self unless block_given?
|
|
44
|
+
|
|
45
|
+
pool ||= ChefUtils::DefaultThreadPool.instance.pool
|
|
46
|
+
|
|
47
|
+
futures = map do |item|
|
|
48
|
+
future = Concurrent::Future.execute(executor: pool) do
|
|
49
|
+
yield item
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
futures.map(&:value!)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# This has the same behavior as parallel_map but returns the enumerator instead of
|
|
57
|
+
# the return values.
|
|
58
|
+
#
|
|
59
|
+
# @return [Enumerable] the enumerable for method chaining
|
|
60
|
+
#
|
|
61
|
+
def parallel_each(pool: nil, &block)
|
|
62
|
+
return self unless block_given?
|
|
63
|
+
|
|
64
|
+
parallel_map(pool: pool, &block)
|
|
65
|
+
|
|
66
|
+
self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# The flat_each method is tightly coupled to the usage of parallel_map within the
|
|
70
|
+
# ChefFS implementation. It is not itself a parallel method, but it is used to
|
|
71
|
+
# iterate through the 2nd level of nested structure, which is tied to the nested
|
|
72
|
+
# structures that ChefFS returns.
|
|
73
|
+
#
|
|
74
|
+
# This is different from Enumerable#flat_map because that behaves like map.flatten(1) while
|
|
75
|
+
# this behaves more like flatten(1).each. We need this on an Enumerable, so we have no
|
|
76
|
+
# Enumerable#flatten method to call.
|
|
77
|
+
#
|
|
78
|
+
# [ [ 1, 2 ], [ 3, 4 ] ].flat_each(&block) calls block four times with 1, 2, 3, 4
|
|
79
|
+
#
|
|
80
|
+
# [ [ 1, 2 ], [ 3, 4 ] ].flat_map(&block) calls block twice with [1, 2] and [3,4]
|
|
81
|
+
#
|
|
82
|
+
def flat_each(&block)
|
|
83
|
+
map do |value|
|
|
84
|
+
if value.is_a?(Enumerable)
|
|
85
|
+
value.each(&block)
|
|
86
|
+
else
|
|
87
|
+
yield value
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The DefaultThreadPool has a fixed thread size and has no
|
|
95
|
+
# queue of work and the behavior on failure to find a thread is for the
|
|
96
|
+
# caller to run the work. This contract means that the thread pool can
|
|
97
|
+
# be called recursively without deadlocking and while keeping the fixed
|
|
98
|
+
# number of threads (and not exponentially growing the thread pool with
|
|
99
|
+
# the depth of recursion).
|
|
100
|
+
#
|
|
101
|
+
class DefaultThreadPool
|
|
102
|
+
include Singleton
|
|
103
|
+
|
|
104
|
+
DEFAULT_THREAD_SIZE = 10
|
|
105
|
+
|
|
106
|
+
# Size of the thread pool, must be set before getting the thread pool or
|
|
107
|
+
# calling parallel_map/parallel_each. Does not (but could be modified to)
|
|
108
|
+
# support dynamic resizing. To get fully synchronous behavior set this equal to
|
|
109
|
+
# zero rather than one since the caller will get work if the threads are
|
|
110
|
+
# busy.
|
|
111
|
+
#
|
|
112
|
+
# @return [Integer] number of threads
|
|
113
|
+
attr_accessor :threads
|
|
114
|
+
|
|
115
|
+
# Memoizing accessor for the thread pool
|
|
116
|
+
#
|
|
117
|
+
# @return [Concurrent::ThreadPoolExecutor] the thread pool
|
|
118
|
+
def pool
|
|
119
|
+
@pool ||= Concurrent::ThreadPoolExecutor.new(
|
|
120
|
+
min_threads: threads || DEFAULT_THREAD_SIZE,
|
|
121
|
+
max_threads: threads || DEFAULT_THREAD_SIZE,
|
|
122
|
+
max_queue: 0,
|
|
123
|
+
# "synchronous" redefines the 0 in max_queue to mean 'no queue' instead of 'infinite queue'
|
|
124
|
+
# it does not mean synchronous execution (no threads) but synchronous offload to the threads.
|
|
125
|
+
synchronous: true,
|
|
126
|
+
# this prevents deadlocks on recursive parallel usage
|
|
127
|
+
fallback_policy: :caller_runs
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
data/lib/chef-utils/version.rb
CHANGED
data/spec/unit/dsl/cloud_spec.rb
CHANGED
|
@@ -45,6 +45,10 @@ RSpec.describe ChefUtils::DSL::Cloud do
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
context "on alibaba" do
|
|
49
|
+
cloud_reports_true_for(:cloud?, :alibaba?, node: { "alibaba" => {}, "cloud" => {} })
|
|
50
|
+
end
|
|
51
|
+
|
|
48
52
|
context "on ec2" do
|
|
49
53
|
cloud_reports_true_for(:cloud?, :ec2?, node: { "ec2" => {}, "cloud" => {} })
|
|
50
54
|
end
|
|
@@ -32,6 +32,18 @@ RSpec.describe ChefUtils::DSL::Introspection do
|
|
|
32
32
|
|
|
33
33
|
let(:test_instance) { IntrospectionTestClass.new(node) }
|
|
34
34
|
|
|
35
|
+
context "#effortless?" do
|
|
36
|
+
# FIXME: use a real VividMash for these tests instead of stubbing
|
|
37
|
+
it "is false by default" do
|
|
38
|
+
expect(node).to receive(:read).with("chef_packages", "chef", "chef_effortless").and_return(nil)
|
|
39
|
+
expect(ChefUtils.effortless?(node)).to be false
|
|
40
|
+
end
|
|
41
|
+
it "is true when ohai reports a effortless" do
|
|
42
|
+
expect(node).to receive(:read).with("chef_packages", "chef", "chef_effortless").and_return(true)
|
|
43
|
+
expect(ChefUtils.effortless?(node)).to be true
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
35
47
|
context "#docker?" do
|
|
36
48
|
# FIXME: use a real VividMash for these tests instead of stubbing
|
|
37
49
|
it "is false by default" do
|
|
@@ -90,13 +90,13 @@ RSpec.describe ChefUtils::DSL::PlatformFamily do
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
context "on centos6" do
|
|
93
|
-
let(:options) { { platform: "centos", version: "6
|
|
93
|
+
let(:options) { { platform: "centos", version: "6" } }
|
|
94
94
|
|
|
95
95
|
pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
context "on centos7" do
|
|
99
|
-
let(:options) { { platform: "centos", version: "7
|
|
99
|
+
let(:options) { { platform: "centos", version: "7" } }
|
|
100
100
|
|
|
101
101
|
pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
|
|
102
102
|
end
|
|
@@ -108,7 +108,7 @@ RSpec.describe ChefUtils::DSL::PlatformFamily do
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
context "on clearos7" do
|
|
111
|
-
let(:options) { { platform: "clearos", version: "7
|
|
111
|
+
let(:options) { { platform: "clearos", version: "7" } }
|
|
112
112
|
|
|
113
113
|
pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
|
|
114
114
|
end
|
|
@@ -156,25 +156,25 @@ RSpec.describe ChefUtils::DSL::PlatformFamily do
|
|
|
156
156
|
end
|
|
157
157
|
|
|
158
158
|
context "on oracle6" do
|
|
159
|
-
let(:options) { { platform: "oracle", version: "6
|
|
159
|
+
let(:options) { { platform: "oracle", version: "6" } }
|
|
160
160
|
|
|
161
161
|
pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
|
|
162
162
|
end
|
|
163
163
|
|
|
164
164
|
context "on oracle7" do
|
|
165
|
-
let(:options) { { platform: "oracle", version: "7
|
|
165
|
+
let(:options) { { platform: "oracle", version: "7" } }
|
|
166
166
|
|
|
167
167
|
pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
|
|
168
168
|
end
|
|
169
169
|
|
|
170
170
|
context "on redhat6" do
|
|
171
|
-
let(:options) { { platform: "redhat", version: "6
|
|
171
|
+
let(:options) { { platform: "redhat", version: "6" } }
|
|
172
172
|
|
|
173
173
|
pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel6?)
|
|
174
174
|
end
|
|
175
175
|
|
|
176
176
|
context "on redhat7" do
|
|
177
|
-
let(:options) { { platform: "redhat", version: "7
|
|
177
|
+
let(:options) { { platform: "redhat", version: "7" } }
|
|
178
178
|
|
|
179
179
|
pf_reports_true_for(:rhel?, :rpm_based?, :fedora_derived?, :redhat_based?, :el?, :rhel7?)
|
|
180
180
|
end
|
|
@@ -145,6 +145,20 @@ RSpec.describe ChefUtils::DSL::Platform do
|
|
|
145
145
|
platform_reports_true_for(:centos?, :centos_platform?)
|
|
146
146
|
end
|
|
147
147
|
|
|
148
|
+
context "on centos stream w/o os_release" do
|
|
149
|
+
let(:options) { { platform: "centos" } }
|
|
150
|
+
let(:node) { { "platform" => "centos", "platform_version" => "8", "platform_family" => "rhel", "os" => "linux", "lsb" => { "id" => "CentOSStream" }, "os_release" => nil } }
|
|
151
|
+
|
|
152
|
+
platform_reports_true_for(:centos?, :centos_platform?, :centos_stream_platform?)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
context "on centos stream w/ os_release" do
|
|
156
|
+
let(:options) { { platform: "centos" } }
|
|
157
|
+
let(:node) { { "platform" => "centos", "platform_version" => "8", "platform_family" => "rhel", "os" => "linux", "os_release" => { "name" => "CentOS Stream" } } }
|
|
158
|
+
|
|
159
|
+
platform_reports_true_for(:centos?, :centos_platform?, :centos_stream_platform?)
|
|
160
|
+
end
|
|
161
|
+
|
|
148
162
|
context "on clearos" do
|
|
149
163
|
let(:options) { { platform: "clearos" } }
|
|
150
164
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
#
|
|
3
|
+
# Copyright:: Copyright (c) Chef Software Inc.
|
|
4
|
+
# License:: Apache License, Version 2.0
|
|
5
|
+
#
|
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
# you may not use this file except in compliance with the License.
|
|
8
|
+
# You may obtain a copy of the License at
|
|
9
|
+
#
|
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
#
|
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
# See the License for the specific language governing permissions and
|
|
16
|
+
# limitations under the License.
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
require "chef-utils/parallel_map"
|
|
20
|
+
|
|
21
|
+
using ChefUtils::ParallelMap
|
|
22
|
+
|
|
23
|
+
RSpec.describe ChefUtils::ParallelMap do
|
|
24
|
+
|
|
25
|
+
shared_examples_for "common parallel API tests" do
|
|
26
|
+
|
|
27
|
+
before(:each) do
|
|
28
|
+
ChefUtils::DefaultThreadPool.instance.instance_variable_set(:@pool, nil)
|
|
29
|
+
ChefUtils::DefaultThreadPool.instance.threads = threads
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
after(:each) do
|
|
33
|
+
ChefUtils::DefaultThreadPool.instance.instance_variable_set(:@pool, nil)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "parallel_map runs in parallel" do
|
|
37
|
+
# this is implicitly also testing that we run in the caller when we exhaust threads by running threads+1
|
|
38
|
+
val = threads + 1
|
|
39
|
+
ret = []
|
|
40
|
+
start = Time.now
|
|
41
|
+
(1..val).parallel_map do |i|
|
|
42
|
+
loop do
|
|
43
|
+
if val == i
|
|
44
|
+
ret << i
|
|
45
|
+
val -= 1
|
|
46
|
+
break
|
|
47
|
+
end
|
|
48
|
+
# we spin for quite awhile to wait for very slow testers if we have to
|
|
49
|
+
if Time.now - start > 30
|
|
50
|
+
raise "timed out; deadlocked due to lack of parallelization?"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# need to sleep a tiny bit to let other threads schedule
|
|
54
|
+
sleep 0.000001
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
expected = (1..threads + 1).to_a.reverse
|
|
58
|
+
expect(ret).to eql(expected)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "parallel_each runs in parallel" do
|
|
62
|
+
# this is implicitly also testing that we run in the caller when we exhaust threads by running threads+1
|
|
63
|
+
val = threads + 1
|
|
64
|
+
ret = []
|
|
65
|
+
start = Time.now
|
|
66
|
+
(1..val).parallel_each do |i|
|
|
67
|
+
loop do
|
|
68
|
+
if val == i
|
|
69
|
+
ret << i
|
|
70
|
+
val -= 1
|
|
71
|
+
break
|
|
72
|
+
end
|
|
73
|
+
# we spin for quite awhile to wait for very slow testers if we have to
|
|
74
|
+
if Time.now - start > 30
|
|
75
|
+
raise "timed out; deadlocked due to lack of parallelization?"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# need to sleep a tiny bit to let other threads schedule
|
|
79
|
+
sleep 0.000001
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
expected = (1..threads + 1).to_a.reverse
|
|
83
|
+
expect(ret).to eql(expected)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "parallel_map throws exceptions" do
|
|
87
|
+
expect { (0..10).parallel_map { |i| raise "boom" } }.to raise_error(RuntimeError)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "parallel_each throws exceptions" do
|
|
91
|
+
expect { (0..10).parallel_each { |i| raise "boom" } }.to raise_error(RuntimeError)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "parallel_map runs" do
|
|
95
|
+
ans = Timeout.timeout(30) do
|
|
96
|
+
(1..10).parallel_map { |i| i }
|
|
97
|
+
end
|
|
98
|
+
expect(ans).to eql((1..10).to_a)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "parallel_each runs" do
|
|
102
|
+
Timeout.timeout(30) do
|
|
103
|
+
(1..10).parallel_each { |i| i }
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "recursive parallel_map will not deadlock" do
|
|
108
|
+
ans = Timeout.timeout(30) do
|
|
109
|
+
(1..2).parallel_map { |i| (1..2).parallel_map { |i| i } }
|
|
110
|
+
end
|
|
111
|
+
expect(ans).to eql([[1, 2], [1, 2]])
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "recursive parallel_each will not deadlock" do
|
|
115
|
+
ans = Timeout.timeout(30) do
|
|
116
|
+
(1..2).parallel_each { |i| (1..2).parallel_each { |i| i } }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "parallel_map is lazy" do
|
|
121
|
+
ans = Timeout.timeout(30) do
|
|
122
|
+
(1..).lazy.parallel_map { |i| i }.first(5)
|
|
123
|
+
end
|
|
124
|
+
expect(ans).to eql((1..5).to_a)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "parallel_each is lazy" do
|
|
128
|
+
ans = Timeout.timeout(30) do
|
|
129
|
+
(1..).lazy.parallel_each { |i| i }.first(5)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "with 10 threads" do
|
|
135
|
+
let(:threads) { 10 }
|
|
136
|
+
it_behaves_like "common parallel API tests"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
context "with 0 threads" do
|
|
140
|
+
let(:threads) { 0 }
|
|
141
|
+
it_behaves_like "common parallel API tests"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
context "with 1 threads" do
|
|
145
|
+
let(:threads) { 1 }
|
|
146
|
+
it_behaves_like "common parallel API tests"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
context "flat_each" do
|
|
150
|
+
it "runs each over items which are nested one level" do
|
|
151
|
+
sum = 0
|
|
152
|
+
[ [ 1, 2 ], [3, 4]].flat_each { |i| sum += i }
|
|
153
|
+
expect(sum).to eql(10)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
metadata
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chef-utils
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 17.2.29
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chef Software, Inc
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
12
|
-
dependencies:
|
|
11
|
+
date: 2021-06-09 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: concurrent-ruby
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0'
|
|
13
27
|
description:
|
|
14
28
|
email:
|
|
15
29
|
- oss@chef.io
|
|
@@ -38,6 +52,7 @@ files:
|
|
|
38
52
|
- lib/chef-utils/dsl/windows.rb
|
|
39
53
|
- lib/chef-utils/internal.rb
|
|
40
54
|
- lib/chef-utils/mash.rb
|
|
55
|
+
- lib/chef-utils/parallel_map.rb
|
|
41
56
|
- lib/chef-utils/version.rb
|
|
42
57
|
- lib/chef-utils/version_string.rb
|
|
43
58
|
- spec/spec_helper.rb
|
|
@@ -54,6 +69,7 @@ files:
|
|
|
54
69
|
- spec/unit/dsl/which_spec.rb
|
|
55
70
|
- spec/unit/dsl/windows_spec.rb
|
|
56
71
|
- spec/unit/mash_spec.rb
|
|
72
|
+
- spec/unit/parallel_map_spec.rb
|
|
57
73
|
homepage: https://github.com/chef/chef/tree/master/chef-utils
|
|
58
74
|
licenses:
|
|
59
75
|
- Apache-2.0
|
|
@@ -71,14 +87,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
71
87
|
requirements:
|
|
72
88
|
- - ">="
|
|
73
89
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 2.6
|
|
90
|
+
version: '2.6'
|
|
75
91
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
92
|
requirements:
|
|
77
93
|
- - ">="
|
|
78
94
|
- !ruby/object:Gem::Version
|
|
79
95
|
version: '0'
|
|
80
96
|
requirements: []
|
|
81
|
-
rubygems_version: 3.
|
|
97
|
+
rubygems_version: 3.2.15
|
|
82
98
|
signing_key:
|
|
83
99
|
specification_version: 4
|
|
84
100
|
summary: Basic utility functions for Core Chef Infra development
|