dream-ops 0.4.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +41 -1
- data/README.md +9 -8
- data/dream-ops.gemspec +10 -6
- data/lib/dream-ops.rb +26 -0
- data/lib/dream-ops/cli.rb +10 -1
- data/lib/dream-ops/deployment/base.rb +17 -1
- data/lib/dream-ops/deployment/opsworks.rb +7 -2
- data/lib/dream-ops/deployment/solo.rb +31 -17
- data/lib/dream-ops/errors.rb +12 -4
- data/lib/dream-ops/init/solo.rb +13 -11
- data/lib/dream-ops/utils/threaded_enum.rb +81 -0
- data/lib/dream-ops/version.rb +1 -1
- metadata +64 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8b007fcf3a075614dc42f84cc722ccf4f4de27e5
|
4
|
+
data.tar.gz: 04a440399ff9dbb2cac9b9b99d9c6815c37becb2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93bb6a02da4398fcb4546f51b0f084374356a0622fba41fd0b5409f2452d656424ea066d10762bc4534d4313ec05d2a2e418986e999f064b654a6193326a8077
|
7
|
+
data.tar.gz: 9d21948bda4ed935798c203d15c3a9f8e2b6457a87dbb6aba250dd56c40dc4b46910d1b18a816d95d2943250e93299ef6916f7749e80f9db84b80ca6cc132181
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,40 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [0.7.0]
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
- Updated to use Chef Workstation instead of ChefDK
|
13
|
+
|
14
|
+
### Fixes
|
15
|
+
- Adds `solo` support for Ubuntu 20.04
|
16
|
+
|
17
|
+
## [0.6.1]
|
18
|
+
|
19
|
+
### Fixes
|
20
|
+
- Now using thread-safe enum to avoid `FiberError`
|
21
|
+
|
22
|
+
## [0.6.0]
|
23
|
+
|
24
|
+
### Added
|
25
|
+
- Added global `aws_profile` option
|
26
|
+
- Added spinner to all deployments to avoid CI hangs
|
27
|
+
|
28
|
+
## [0.5.0]
|
29
|
+
|
30
|
+
### Changed
|
31
|
+
- **BREAKING CHANGE**: Removed syncing of code for `solo` deployments
|
32
|
+
|
33
|
+
## [0.4.2]
|
34
|
+
|
35
|
+
### Changed
|
36
|
+
- SSH options now set `LogLevel=ERROR`
|
37
|
+
|
38
|
+
## [0.4.1]
|
39
|
+
|
40
|
+
### Changed
|
41
|
+
- Silences stderr for _all_ ssh commands
|
42
|
+
|
9
43
|
## [0.4.0]
|
10
44
|
|
11
45
|
### Changed
|
@@ -39,7 +73,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
39
73
|
- Gem version badge to README
|
40
74
|
- Usage documentation
|
41
75
|
|
42
|
-
[Unreleased]: https://github.com/chris-allen/dream-ops/compare/v0.
|
76
|
+
[Unreleased]: https://github.com/chris-allen/dream-ops/compare/v0.7.0...HEAD
|
77
|
+
[0.7.0]: https://github.com/chris-allen/dream-ops/compare/v0.6.1...v0.7.0
|
78
|
+
[0.6.1]: https://github.com/chris-allen/dream-ops/compare/v0.6.0...v0.6.1
|
79
|
+
[0.6.0]: https://github.com/chris-allen/dream-ops/compare/v0.5.0...v0.6.0
|
80
|
+
[0.5.0]: https://github.com/chris-allen/dream-ops/compare/v0.4.2...v0.5.0
|
81
|
+
[0.4.2]: https://github.com/chris-allen/dream-ops/compare/v0.4.1...v0.4.2
|
82
|
+
[0.4.1]: https://github.com/chris-allen/dream-ops/compare/v0.4.0...v0.4.1
|
43
83
|
[0.4.0]: https://github.com/chris-allen/dream-ops/compare/v0.3.0...v0.4.0
|
44
84
|
[0.3.0]: https://github.com/chris-allen/dream-ops/compare/v0.2.0...v0.3.0
|
45
85
|
[0.2.0]: https://github.com/chris-allen/dream-ops/compare/v0.1.0...v0.2.0
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# DreamOps
|
2
2
|
[![Gem Version](https://img.shields.io/gem/v/dream-ops.svg)][gem]
|
3
|
-
[![Build Status](https://travis-ci.
|
3
|
+
[![Build Status](https://travis-ci.com/chris-allen/dream-ops.svg?branch=master)](https://travis-ci.com/chris-allen/dream-ops)
|
4
4
|
|
5
5
|
[gem]: https://rubygems.org/gems/dream-ops
|
6
6
|
|
@@ -33,11 +33,12 @@ Commands:
|
|
33
33
|
dream version # Display version
|
34
34
|
|
35
35
|
Options:
|
36
|
-
-F, [--format=FORMAT]
|
37
|
-
|
38
|
-
-q, [--quiet], [--no-quiet]
|
39
|
-
-d, [--debug], [--no-debug]
|
40
|
-
-i, [--ssh-key=SSH_KEY]
|
36
|
+
-F, [--format=FORMAT] # Output format to use.
|
37
|
+
# Default: human
|
38
|
+
-q, [--quiet], [--no-quiet] # Silence all informational output.
|
39
|
+
-d, [--debug], [--no-debug] # Output debug information
|
40
|
+
-i, [--ssh-key=SSH_KEY] # Path to SSH key
|
41
|
+
-p, [--aws-profile=AWS_PROFILE] # AWS profile to use
|
41
42
|
|
42
43
|
```
|
43
44
|
|
@@ -73,11 +74,11 @@ Target: ip-172-31-53-232
|
|
73
74
|
```bash
|
74
75
|
dream init solo -T ubuntu@example.com -i /path/to/key.pem
|
75
76
|
Target: ip-172-31-53-232
|
76
|
-
---
|
77
|
+
--- Chef Workstation Installed: false
|
77
78
|
--- Valid chef.json: false
|
78
79
|
--- Valid role[setup]: false
|
79
80
|
--- Valid role[deploy]: false
|
80
|
-
...Installing
|
81
|
+
...Installing Chef Workstation [target="ubuntu@example.com"]
|
81
82
|
...Creating boilerplate /var/chef/chef.json [target="ubuntu@example.com"]
|
82
83
|
...Creating boilerplate /var/chef/roles/setup.json [target="ubuntu@example.com"]
|
83
84
|
...Creating boilerplate /var/chef/roles/deploy.json [target="ubuntu@example.com"]
|
data/dream-ops.gemspec
CHANGED
@@ -31,12 +31,16 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
32
|
spec.require_paths = ["lib"]
|
33
33
|
|
34
|
-
spec.add_development_dependency "bundler", "~>
|
34
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
35
35
|
spec.add_development_dependency "rake", "~> 10.0"
|
36
36
|
|
37
|
-
spec.add_dependency "rubyzip",
|
38
|
-
spec.add_dependency "aws-sdk"
|
39
|
-
spec.add_dependency "
|
40
|
-
spec.add_dependency "
|
41
|
-
spec.add_dependency "
|
37
|
+
spec.add_dependency "rubyzip", "~> 1.2"
|
38
|
+
spec.add_dependency "aws-sdk-core"
|
39
|
+
spec.add_dependency "aws-sdk-configservice", "~> 1"
|
40
|
+
spec.add_dependency "aws-sdk-opsworks", "~> 1"
|
41
|
+
spec.add_dependency "aws-sdk-s3", "~> 1"
|
42
|
+
spec.add_dependency "inifile", "~> 3.0"
|
43
|
+
spec.add_dependency "berkshelf", "~> 7.0"
|
44
|
+
spec.add_dependency "thor", "~> 0.20"
|
45
|
+
spec.add_dependency "chef", "~> 13.6"
|
42
46
|
end
|
data/lib/dream-ops.rb
CHANGED
@@ -10,6 +10,9 @@ end
|
|
10
10
|
|
11
11
|
require "berkshelf"
|
12
12
|
require "thor"
|
13
|
+
require "aws-sdk-core"
|
14
|
+
require "aws-sdk-configservice"
|
15
|
+
require "inifile"
|
13
16
|
|
14
17
|
module DreamOps
|
15
18
|
|
@@ -76,6 +79,29 @@ module DreamOps
|
|
76
79
|
@ssh_key = key
|
77
80
|
end
|
78
81
|
|
82
|
+
# Specify AWS profile to use
|
83
|
+
def use_aws_profile(profile)
|
84
|
+
begin
|
85
|
+
shared_creds = Aws::SharedCredentials.new(profile_name: profile)
|
86
|
+
Aws.config.update(credentials: shared_creds)
|
87
|
+
rescue Aws::Errors::NoSuchProfileError => error
|
88
|
+
DreamOps.ui.error error
|
89
|
+
exit(1)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Unfortunately, Aws::OpsWorks::Client only loads the default profile's
|
93
|
+
# region. This parses the INI files and honors the profile region if set.
|
94
|
+
ini = IniFile.load("#{ENV['HOME']}/.aws/config")
|
95
|
+
if ini.nil? || !ini.has_section(profile)
|
96
|
+
ini = IniFile.load("#{ENV['HOME']}/.aws/credentials")
|
97
|
+
end
|
98
|
+
|
99
|
+
region = ini.to_h[profile]['region']
|
100
|
+
if !region.nil? && !region.empty?
|
101
|
+
Aws.config.update(region: region)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
79
105
|
# Get whether to always run setup
|
80
106
|
#
|
81
107
|
# @return [~boolean]
|
data/lib/dream-ops/cli.rb
CHANGED
@@ -65,10 +65,14 @@ module DreamOps
|
|
65
65
|
|
66
66
|
DreamOps.set_format @options[:format]
|
67
67
|
|
68
|
-
if
|
68
|
+
if !@options[:ssh_key].empty?
|
69
69
|
DreamOps.set_ssh_key @options[:ssh_key]
|
70
70
|
end
|
71
71
|
|
72
|
+
if !@options[:aws_profile].empty?
|
73
|
+
DreamOps.use_aws_profile @options[:aws_profile]
|
74
|
+
end
|
75
|
+
|
72
76
|
@options = options.dup # unfreeze frozen options Hash from Thor
|
73
77
|
end
|
74
78
|
|
@@ -100,6 +104,11 @@ module DreamOps
|
|
100
104
|
desc: "Path to SSH key",
|
101
105
|
aliases: "-i",
|
102
106
|
default: ""
|
107
|
+
class_option :aws_profile,
|
108
|
+
type: :string,
|
109
|
+
desc: "AWS profile to use",
|
110
|
+
aliases: "-p",
|
111
|
+
default: ""
|
103
112
|
|
104
113
|
desc "version", "Display version"
|
105
114
|
def version
|
@@ -1,8 +1,19 @@
|
|
1
|
-
require
|
1
|
+
require 'dream-ops/utils/zip'
|
2
|
+
require 'dream-ops/utils/threaded_enum'
|
2
3
|
require 'fileutils'
|
3
4
|
|
4
5
|
module DreamOps
|
5
6
|
class BaseDeployer
|
7
|
+
|
8
|
+
@@spinner = ThreadedEnum.new do |e|
|
9
|
+
loop do
|
10
|
+
e << '|'
|
11
|
+
e << '/'
|
12
|
+
e << '-'
|
13
|
+
e << '\\'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
6
17
|
class << self
|
7
18
|
#
|
8
19
|
# @macro deployer_method
|
@@ -96,6 +107,11 @@ module DreamOps
|
|
96
107
|
end
|
97
108
|
|
98
109
|
def deploy(*args)
|
110
|
+
# Ensure git is installed
|
111
|
+
if (!system("which git > /dev/null 2>&1"))
|
112
|
+
__bail_with_fatal_error(GitNotInstalledError.new)
|
113
|
+
end
|
114
|
+
|
99
115
|
# Find unique cookbooks and deploy targets
|
100
116
|
result = analyze(args)
|
101
117
|
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require "aws-sdk"
|
1
|
+
require "aws-sdk-opsworks"
|
2
|
+
require "aws-sdk-s3"
|
2
3
|
require "uri"
|
3
4
|
|
4
5
|
Aws.use_bundled_cert!
|
@@ -240,8 +241,12 @@ module DreamOps
|
|
240
241
|
status = "failed"
|
241
242
|
while true
|
242
243
|
status = get_deployment_status(deployment_id)
|
243
|
-
|
244
|
+
if ["successful", "failed"].include? status
|
245
|
+
print "\b"
|
246
|
+
break
|
247
|
+
end
|
244
248
|
sleep(2)
|
249
|
+
print "\r#{@@spinner.next}"
|
245
250
|
end
|
246
251
|
return status
|
247
252
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'securerandom'
|
2
|
+
require 'timeout'
|
2
3
|
|
3
4
|
module DreamOps
|
4
5
|
class SoloDeployer < BaseDeployer
|
@@ -10,6 +11,20 @@ module DreamOps
|
|
10
11
|
return cookbooks.any? {|c| c[:targets].include? target }
|
11
12
|
end
|
12
13
|
|
14
|
+
def __wait_for_pid(pid)
|
15
|
+
while true do
|
16
|
+
begin
|
17
|
+
Timeout.timeout(5) do
|
18
|
+
Process.wait pid
|
19
|
+
end
|
20
|
+
print "\b"
|
21
|
+
return $?.exitstatus == 0
|
22
|
+
rescue Timeout::Error
|
23
|
+
print "\r#{@@spinner.next}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
13
28
|
# Analyze the SSH hosts for deployment
|
14
29
|
#
|
15
30
|
# @return [Hash]
|
@@ -37,7 +52,7 @@ module DreamOps
|
|
37
52
|
# ]
|
38
53
|
# }
|
39
54
|
def analyze(targets)
|
40
|
-
@ssh_opts = "-i #{DreamOps.ssh_key} -o
|
55
|
+
@ssh_opts = "-i #{DreamOps.ssh_key} -o LogLevel=ERROR -o StrictHostKeyChecking=no"
|
41
56
|
@q_all = "> /dev/null 2>&1"
|
42
57
|
@q_stdout = "> /dev/null"
|
43
58
|
|
@@ -146,27 +161,26 @@ module DreamOps
|
|
146
161
|
|
147
162
|
uuid = SecureRandom.uuid
|
148
163
|
|
149
|
-
|
150
|
-
|
151
|
-
"
|
152
|
-
|
153
|
-
|
164
|
+
pid = fork do
|
165
|
+
if ! system(
|
166
|
+
"ssh #{@ssh_opts} #{target[:host]} \"" +
|
167
|
+
"set -o pipefail && " +
|
168
|
+
"sudo chef-solo --chef-license accept -j /var/chef/chef.json -o \"role[#{role}]\" 2>&1 | sudo tee /var/log/chef/#{uuid}.log #{@q_all}\""
|
169
|
+
)
|
170
|
+
exit 1
|
171
|
+
end
|
172
|
+
exit 0
|
173
|
+
end
|
174
|
+
|
175
|
+
if !__wait_for_pid(pid)
|
154
176
|
__bail_with_fatal_error(ChefSoloFailedError.new(target[:host], "/var/log/chef/#{uuid}.log"))
|
155
177
|
end
|
156
178
|
end
|
157
179
|
|
158
|
-
# Deploy latest code
|
159
180
|
def deploy_target(target, cookbooks)
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
DreamOps.ui.info "...Syncing [repo=\"#{repo_name}\" target=\"#{target[:host]}\"]"
|
164
|
-
`rsync -r -e "ssh #{@ssh_opts}" . #{target[:host]}:~/#{repo_name}`
|
165
|
-
|
166
|
-
|
167
|
-
# Bail if ChefDK is not installed
|
168
|
-
if !system("ssh #{@ssh_opts} #{target[:host]} which chef #{@q_stdout}")
|
169
|
-
__bail_with_fatal_error(ChefDKNotInstalledError.new(target[:host]))
|
181
|
+
# Bail if Chef Workstation is not installed
|
182
|
+
if !system("ssh #{@ssh_opts} #{target[:host]} which chef #{@q_all}")
|
183
|
+
__bail_with_fatal_error(ChefWorkstationNotInstalledError.new(target[:host]))
|
170
184
|
end
|
171
185
|
|
172
186
|
# Bail if chef.json doesn't exist
|
data/lib/dream-ops/errors.rb
CHANGED
@@ -66,7 +66,7 @@ module DreamOps
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
class
|
69
|
+
class ChefWorkstationNotInstalledError < DreamOpsError
|
70
70
|
set_status_code(14)
|
71
71
|
|
72
72
|
def initialize(target)
|
@@ -75,14 +75,14 @@ module DreamOps
|
|
75
75
|
|
76
76
|
def to_s
|
77
77
|
[
|
78
|
-
"
|
78
|
+
"Chef Workstation not installed on target \"#{@target}\". To initialize chef-solo, run:",
|
79
79
|
"",
|
80
80
|
"dream init solo -t #{@target} -i #{DreamOps.ssh_key}",
|
81
81
|
].join("\n")
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
class
|
85
|
+
class ChefWorkstationFailedError < DreamOpsError
|
86
86
|
set_status_code(15)
|
87
87
|
|
88
88
|
def initialize(target, wget_url)
|
@@ -92,7 +92,7 @@ module DreamOps
|
|
92
92
|
|
93
93
|
def to_s
|
94
94
|
[
|
95
|
-
"Target \"#{@target}\" failed installing
|
95
|
+
"Target \"#{@target}\" failed installing ChefWorkstation from:",
|
96
96
|
"",
|
97
97
|
@wget_url,
|
98
98
|
].join("\n")
|
@@ -148,4 +148,12 @@ module DreamOps
|
|
148
148
|
].join("\n")
|
149
149
|
end
|
150
150
|
end
|
151
|
+
|
152
|
+
class GitNotInstalledError < DreamOpsError
|
153
|
+
set_status_code(19)
|
154
|
+
|
155
|
+
def to_s
|
156
|
+
"Unabled to find git in your PATH."
|
157
|
+
end
|
158
|
+
end
|
151
159
|
end
|
data/lib/dream-ops/init/solo.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module DreamOps
|
2
2
|
class SoloInitializer < BaseInitializer
|
3
3
|
def analyze(targets)
|
4
|
-
@ssh_opts = "-i #{DreamOps.ssh_key} -o
|
4
|
+
@ssh_opts = "-i #{DreamOps.ssh_key} -o LogLevel=ERROR -o StrictHostKeyChecking=no"
|
5
5
|
@q_all = "> /dev/null 2>&1"
|
6
6
|
@q_stdout = "> /dev/null"
|
7
7
|
|
@@ -21,8 +21,8 @@ module DreamOps
|
|
21
21
|
|
22
22
|
target_result = { host: target }
|
23
23
|
|
24
|
-
target_result[:chefdk_installed] = system("ssh #{@ssh_opts} #{target} which chef #{@
|
25
|
-
DreamOps.ui.info "---
|
24
|
+
target_result[:chefdk_installed] = system("ssh #{@ssh_opts} #{target} which chef #{@q_all}")
|
25
|
+
DreamOps.ui.info "--- Chef Workstation Installed: #{target_result[:chefdk_installed]}"
|
26
26
|
|
27
27
|
target_result[:solo_json_exists] = system("ssh #{@ssh_opts} #{target} stat /var/chef/chef.json #{@q_all}")
|
28
28
|
DreamOps.ui.info "--- Valid chef.json: #{target_result[:solo_json_exists]}"
|
@@ -40,23 +40,25 @@ module DreamOps
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def init_target(target, dryrun)
|
43
|
-
# Install
|
43
|
+
# Install ChefWorkstation if not already
|
44
44
|
if !target[:chefdk_installed]
|
45
45
|
if dryrun
|
46
|
-
DreamOps.ui.warn "...WOULD Install
|
46
|
+
DreamOps.ui.warn "...WOULD Install Chef Workstation [target=\"#{target[:host]}\"]"
|
47
47
|
else
|
48
|
-
DreamOps.ui.warn "...Installing
|
48
|
+
DreamOps.ui.warn "...Installing Chef Workstation [target=\"#{target[:host]}\"]"
|
49
49
|
|
50
50
|
# Get ubuntu version
|
51
51
|
ubuntu_ver = `ssh #{@ssh_opts} #{target[:host]} "awk 'BEGIN { FS = \\"=\\" } /DISTRIB_RELEASE/ { print \\$2 }' /etc/lsb-release"`.chomp
|
52
52
|
|
53
53
|
# Download and install the package
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
`ssh #{@ssh_opts} #{target[:host]} "sudo
|
54
|
+
deb_file = "chef-workstation_20.12.187-1_amd64.deb"
|
55
|
+
chefworkstation_url = "https://packages.chef.io/files/stable/chef-workstation/20.12.187/ubuntu/#{ubuntu_ver}/#{deb_file}"
|
56
|
+
if system("ssh #{@ssh_opts} #{target[:host]} \"wget #{chefworkstation_url} -P /tmp\" #{@q_all}")
|
57
|
+
`ssh #{@ssh_opts} #{target[:host]} "sudo dpkg -i /tmp/#{deb_file}" #{@q_all}`
|
58
|
+
`ssh #{@ssh_opts} #{target[:host]} "sudo rm /tmp/#{deb_file}" #{@q_all}`
|
59
|
+
`ssh #{@ssh_opts} #{target[:host]} "chef env --chef-license accept" #{@q_all}`
|
58
60
|
else
|
59
|
-
__bail_with_fatal_error(
|
61
|
+
__bail_with_fatal_error(ChefWorkstationFailedError.new(target, chefworkstation_url))
|
60
62
|
end
|
61
63
|
end
|
62
64
|
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Credit: https://github.com/bittrance/rxruby/blob/master/lib/rx/concurrency/threaded_enumerator.rb
|
2
|
+
#
|
3
|
+
# ThreadedEnum can be used across threads unlike Ruby's default Enumerator
|
4
|
+
# that will throw FiberError if the enumerator is used from more than one
|
5
|
+
# thread.
|
6
|
+
class ThreadedEnum
|
7
|
+
ERROR = Object.new
|
8
|
+
DONE = Object.new
|
9
|
+
|
10
|
+
if RUBY_ENGINE == 'jruby'
|
11
|
+
def self.new(*args, &block)
|
12
|
+
Enumerator.new(*args, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# ThreadedEnum helper class
|
17
|
+
class Yielder
|
18
|
+
def initialize(queue, gate, condition)
|
19
|
+
@queue = queue
|
20
|
+
@gate = gate
|
21
|
+
@condition = condition
|
22
|
+
end
|
23
|
+
|
24
|
+
def <<(e)
|
25
|
+
@queue << e
|
26
|
+
@gate.synchronize do
|
27
|
+
@condition.wait @gate while @queue.size > 0
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# The enumerator can be created with either an enumerable or a block that
|
33
|
+
# receives a yielder object, but not both. Note that the block or enumerable
|
34
|
+
# will be iterated immediately once making it possible to prepare the iterator
|
35
|
+
# e.g. when reading from a file or a socket.
|
36
|
+
def initialize(source_or_size_hint = nil, &block)
|
37
|
+
raise TypeError, 'Size hinting not supported' if source_or_size_hint && block_given?
|
38
|
+
@condition = ConditionVariable.new
|
39
|
+
@gate = Mutex.new
|
40
|
+
@queue = Queue.new
|
41
|
+
@done = false
|
42
|
+
setup_yielder(source_or_size_hint, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Receive the next item from the enumerator or any exception thrown from the
|
46
|
+
# enumerator.
|
47
|
+
def next
|
48
|
+
raise StopIteration if @done
|
49
|
+
@gate.synchronize do
|
50
|
+
@condition.signal
|
51
|
+
end
|
52
|
+
payload, type = @queue.pop
|
53
|
+
case type
|
54
|
+
when DONE
|
55
|
+
@done = true
|
56
|
+
raise StopIteration
|
57
|
+
when ERROR
|
58
|
+
@done = true
|
59
|
+
raise payload
|
60
|
+
end
|
61
|
+
payload
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def setup_yielder(source, &block)
|
67
|
+
yielder = Yielder.new(@queue, @gate, @condition)
|
68
|
+
Thread.new do
|
69
|
+
begin
|
70
|
+
if source
|
71
|
+
source.each { |e| yielder << e }
|
72
|
+
else
|
73
|
+
block.call yielder
|
74
|
+
end
|
75
|
+
rescue => e
|
76
|
+
yielder << [e, ERROR]
|
77
|
+
end
|
78
|
+
yielder << [nil, DONE]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/dream-ops/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dream-ops
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Allen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,19 +53,75 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.2'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name: aws-sdk
|
56
|
+
name: aws-sdk-core
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: aws-sdk-configservice
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: aws-sdk-opsworks
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: aws-sdk-s3
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: inifile
|
57
113
|
requirement: !ruby/object:Gem::Requirement
|
58
114
|
requirements:
|
59
115
|
- - "~>"
|
60
116
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
117
|
+
version: '3.0'
|
62
118
|
type: :runtime
|
63
119
|
prerelease: false
|
64
120
|
version_requirements: !ruby/object:Gem::Requirement
|
65
121
|
requirements:
|
66
122
|
- - "~>"
|
67
123
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
124
|
+
version: '3.0'
|
69
125
|
- !ruby/object:Gem::Dependency
|
70
126
|
name: berkshelf
|
71
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -143,6 +199,7 @@ files:
|
|
143
199
|
- lib/dream-ops/logger.rb
|
144
200
|
- lib/dream-ops/mixin/logging.rb
|
145
201
|
- lib/dream-ops/shell.rb
|
202
|
+
- lib/dream-ops/utils/threaded_enum.rb
|
146
203
|
- lib/dream-ops/utils/zip.rb
|
147
204
|
- lib/dream-ops/version.rb
|
148
205
|
homepage: https://github.com/chris-allen/dream-ops
|