chef-utils 16.16.13 → 17.0.242
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/chef-utils.gemspec +5 -1
- 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 +1 -1
- data/lib/chef-utils/dsl/windows.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/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: 8b28b0dd9a34f1242fdeca73f39924515befdec0a2990e4bd56d4d94f071c2aa
|
4
|
+
data.tar.gz: 49cb4691092f6b0db0567a8975e72c3905682208ff0c089fe3149ef8ee8da4d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16f7f528de5d5fb631552951cef5f0e763bffce0c52bb2fb563f8d1cebd16269027dc3a2daf1f151bc58d5901adfb2309d93ecc3b6868e29f75be14b5538511b
|
7
|
+
data.tar.gz: 705ddfa785ecb1a7448a95f342a3718e5f90996131fe2678c6cd15875f3eee5d5cc7d5b7d38fabfa1500c07df26eac804261360cd13b205a7a24435a8a4ee922
|
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/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
|
@@ -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/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
|
@@ -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.0.242
|
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-04-27 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
|