ey_enzyme 0.9.44 → 2.0.7
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 +7 -0
- data/lib/ey_enzyme/api/client.rb +133 -0
- data/lib/ey_enzyme/api.rb +29 -99
- data/lib/ey_enzyme/cli.rb +127 -53
- data/lib/ey_enzyme/cookbook_set.rb +121 -39
- data/lib/ey_enzyme/multi_logger.rb +19 -0
- data/lib/ey_enzyme/version.rb +1 -1
- data/lib/ey_enzyme.rb +2 -4
- metadata +115 -147
- data/bin/ey-recipes +0 -5
- data/lib/ey_enzyme/old_cli.rb +0 -35
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: c71e1af54ddfa6f64786576598b0f828f1528bff
|
|
4
|
+
data.tar.gz: 8586d600ca185ccc67b491393f4b0bba56bd445e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c6e747c25787291bb9dffdf1077a645933885ad23bd5f97df67190ee3c22968dc08f11ad025fc7b84ff44fc8196ad0a0de5088e4c780ffb2db9f157ebbeb7f97
|
|
7
|
+
data.tar.gz: 7ff5be0a8cfc497cabf97c30ff01c0ea497210829dbb71fdaf48414d8ad917ce563610d0e43a2194188937a3e65d91fa877a3a0e14ce13f68ac817bfad801f40
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require 'timeout'
|
|
2
|
+
require 'rest_client'
|
|
3
|
+
|
|
4
|
+
module EY
|
|
5
|
+
module Enzyme
|
|
6
|
+
module API
|
|
7
|
+
class Client
|
|
8
|
+
|
|
9
|
+
REST_TIMEOUT_SECONDS = 60
|
|
10
|
+
TOTAL_TIMEOUT_SECONDS = 600
|
|
11
|
+
RETRY_TIMEOUT_SECONDS = 30
|
|
12
|
+
|
|
13
|
+
attr_reader :api_url, :instance_id, :token, :logger
|
|
14
|
+
|
|
15
|
+
def initialize(api_url, instance_id, token, logger)
|
|
16
|
+
@api_url = api_url
|
|
17
|
+
@instance_id = instance_id
|
|
18
|
+
@token = token
|
|
19
|
+
@logger = logger
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def rest
|
|
23
|
+
@rest ||= RestClient::Resource.new(
|
|
24
|
+
api_url,
|
|
25
|
+
:timeout => REST_TIMEOUT_SECONDS
|
|
26
|
+
)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def report(message)
|
|
30
|
+
safe_api("report", :message => message)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def notify_success
|
|
34
|
+
retry_api("completed", :status => 'true')
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def notify_error(type, error)
|
|
38
|
+
log :exception, "Notifying #{type} error", error
|
|
39
|
+
call_api("error", params_for(type, error))
|
|
40
|
+
rescue RestClient::Exception
|
|
41
|
+
log :exception, "Failed to notify of #{type} error", $!
|
|
42
|
+
raise
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def dna
|
|
46
|
+
retry_api("dna")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def custom_recipe_url
|
|
50
|
+
if response = retry_api("custom-recipe")
|
|
51
|
+
response["url"]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#upload, as in, upload the log file output of the chef run
|
|
56
|
+
def upload(type, file)
|
|
57
|
+
retry_api("store_gzip", :type => type, :file => file)
|
|
58
|
+
rescue => e
|
|
59
|
+
#blanket rescue feels dangerous, but we're at least logging it
|
|
60
|
+
#we don't have all the information we'd like to include in the exception message here anyway
|
|
61
|
+
#caller (CookbookSet#upload) should check return value and notify failure
|
|
62
|
+
api_error("store_gzip", e)
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def log(level, *msg)
|
|
69
|
+
@logger.send(level, *msg) if @logger
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def keys
|
|
73
|
+
@keys ||= {:instance_id => instance_id, :token => token}
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def params_for(type, error)
|
|
77
|
+
{ :class => error.class,
|
|
78
|
+
:message => error.message,
|
|
79
|
+
:backtrace => error.backtrace,
|
|
80
|
+
:where_failed => type }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def call_api(path, opts = {})
|
|
84
|
+
log :debug, "API call path: #{path.inspect}, data: #{opts.inspect}"
|
|
85
|
+
JSON.parse(
|
|
86
|
+
rest[path].post(
|
|
87
|
+
opts.merge(keys),
|
|
88
|
+
{
|
|
89
|
+
:content_type => "application/json",
|
|
90
|
+
:accept => "application/json"
|
|
91
|
+
}
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def retry_api(path, opts={})
|
|
97
|
+
Timeout.timeout(TOTAL_TIMEOUT_SECONDS) do
|
|
98
|
+
loop do
|
|
99
|
+
if result = safe_api(path, opts)
|
|
100
|
+
return result
|
|
101
|
+
end
|
|
102
|
+
sleep RETRY_TIMEOUT_SECONDS
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
rescue Timeout::Error
|
|
106
|
+
false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def safe_api(path, opts = {})
|
|
110
|
+
begin
|
|
111
|
+
return call_api(path, opts)
|
|
112
|
+
rescue RestClient::BadGateway, RestClient::GatewayTimeout
|
|
113
|
+
api_error(path, $!)
|
|
114
|
+
return false
|
|
115
|
+
rescue RestClient::ServiceUnavailable => e
|
|
116
|
+
response = e.response
|
|
117
|
+
if response.headers[:content_type] =~ /json/
|
|
118
|
+
hash = JSON.parse(response)
|
|
119
|
+
log :error, "Failed to fetch DNA: #{hash.delete('message')}: #{hash.inspect}"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
api_error(path, e)
|
|
123
|
+
return false
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def api_error(path, error)
|
|
128
|
+
log :exception, "API request failed", error
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
data/lib/ey_enzyme/api.rb
CHANGED
|
@@ -1,114 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
class API
|
|
3
|
-
def initialize(api_url, instance_id, token, log_file = "/var/log/enzyme.log")
|
|
4
|
-
@api_url = api_url
|
|
5
|
-
@instance_id = instance_id
|
|
6
|
-
@token = token
|
|
7
|
-
@logger = MultiLogger.new(log_file)
|
|
8
|
-
@rest = RestClient::Resource.new(api_url, :timeout => api_rest_timeout_seconds)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
def report(message)
|
|
12
|
-
safe_api("report", :message => message)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def notify_success
|
|
16
|
-
retry_api("completed", :status => 'true')
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def notify_error(type, error)
|
|
20
|
-
@logger.exception "Notifying #{type} error", error
|
|
21
|
-
call_api("error", params_for(type, error))
|
|
22
|
-
rescue RestClient::Exception
|
|
23
|
-
@logger.exception "Failed to notify of #{type} error", $!
|
|
24
|
-
raise
|
|
25
|
-
end
|
|
1
|
+
require 'ey_enzyme/api/client'
|
|
26
2
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def custom_recipe_url
|
|
32
|
-
if response = retry_api("custom-recipe")
|
|
33
|
-
response["url"]
|
|
3
|
+
module EY
|
|
4
|
+
module Enzyme
|
|
5
|
+
module API
|
|
6
|
+
class Unconfigured < StandardError
|
|
34
7
|
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
#upload, as in, upload the log file output of the chef run
|
|
38
|
-
def upload(type, content)
|
|
39
|
-
retry_api("store", :type => type, :content => content)
|
|
40
|
-
rescue => e
|
|
41
|
-
#blanket rescue feels dangerous, but we're at least logging it
|
|
42
|
-
#we don't have all the information we'd like to include in the exception message here anyway
|
|
43
|
-
#caller (CookbookSet#upload) should check return value and notify failure
|
|
44
|
-
api_error("store", e)
|
|
45
|
-
false
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
private
|
|
49
|
-
|
|
50
|
-
def keys
|
|
51
|
-
@keys ||= {:instance_id => @instance_id, :token => @token}
|
|
52
|
-
end
|
|
53
8
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
:where_failed => type }
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
def call_api(path, opts={})
|
|
62
|
-
@logger.debug "API call path: #{path.inspect}, data: #{opts.inspect}"
|
|
63
|
-
JSON.parse(@rest[path].post(opts.merge(keys).to_json,
|
|
64
|
-
{"Content-Type" => "application/json", "Accept" => "application/json"}))
|
|
65
|
-
end
|
|
9
|
+
def self.configure(api_url, instance_id, token, logger)
|
|
10
|
+
@client = Client.new(api_url, instance_id, token, logger)
|
|
11
|
+
self
|
|
12
|
+
end
|
|
66
13
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
14
|
+
def self.client
|
|
15
|
+
raise Unconfigured unless @client
|
|
16
|
+
@client
|
|
17
|
+
end
|
|
70
18
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
19
|
+
def self.report(message)
|
|
20
|
+
client.report(message)
|
|
21
|
+
end
|
|
74
22
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
23
|
+
def self.notify_success
|
|
24
|
+
client.notify_success
|
|
25
|
+
end
|
|
78
26
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
loop do
|
|
82
|
-
if result = safe_api(path, opts)
|
|
83
|
-
return result
|
|
84
|
-
end
|
|
85
|
-
sleep api_sleep_before_retry_seconds
|
|
86
|
-
end
|
|
27
|
+
def self.notify_error(type, error)
|
|
28
|
+
client.notify_error(type, error)
|
|
87
29
|
end
|
|
88
|
-
rescue Timeout::Error
|
|
89
|
-
false
|
|
90
|
-
end
|
|
91
30
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
rescue RestClient::BadGateway, RestClient::GatewayTimeout
|
|
96
|
-
api_error(path, $!)
|
|
97
|
-
return false
|
|
98
|
-
rescue RestClient::ServiceUnavailable => e
|
|
99
|
-
response = e.response
|
|
100
|
-
if response.headers[:content_type] =~ /json/
|
|
101
|
-
hash = JSON.parse(response)
|
|
102
|
-
@logger.error "Failed to fetch DNA: #{hash.delete('message')}: #{hash.inspect}"
|
|
103
|
-
end
|
|
31
|
+
def self.dna
|
|
32
|
+
client.dna
|
|
33
|
+
end
|
|
104
34
|
|
|
105
|
-
|
|
106
|
-
|
|
35
|
+
def self.custom_recipe_url
|
|
36
|
+
client.custom_recipe_url
|
|
107
37
|
end
|
|
108
|
-
end
|
|
109
38
|
|
|
110
|
-
|
|
111
|
-
|
|
39
|
+
def self.upload(type, file)
|
|
40
|
+
client.upload(type, file)
|
|
41
|
+
end
|
|
112
42
|
end
|
|
113
43
|
end
|
|
114
44
|
end
|
data/lib/ey_enzyme/cli.rb
CHANGED
|
@@ -5,44 +5,66 @@ module EY::Enzyme
|
|
|
5
5
|
def self.run(args)
|
|
6
6
|
$stdout.sync = true
|
|
7
7
|
|
|
8
|
-
defaults = {
|
|
9
|
-
|
|
8
|
+
defaults = {
|
|
9
|
+
chef_bin: 'chef-client',
|
|
10
|
+
run_list: ['recipe[ey-init::main]'],
|
|
11
|
+
config: '/etc/engineyard/dracul.yml',
|
|
12
|
+
base_path: '/etc/chef/',
|
|
13
|
+
logfile: '/var/log/ey-enzyme.log',
|
|
14
|
+
log_level: :info,
|
|
15
|
+
keep: 5,
|
|
16
|
+
run_custom: true,
|
|
17
|
+
download: true,
|
|
18
|
+
mode: :deploy
|
|
19
|
+
}
|
|
10
20
|
options = {}
|
|
11
21
|
|
|
12
22
|
opts = OptionParser.new do |opts|
|
|
13
23
|
opts.version = EY::Enzyme::VERSION
|
|
14
|
-
opts.banner = "Usage: ey-enzyme
|
|
24
|
+
opts.banner = "Usage: ey-enzyme <options> [argument]"
|
|
15
25
|
opts.define_head "ey-enzyme: running recipes..."
|
|
16
26
|
opts.separator '*'*80
|
|
17
27
|
|
|
18
|
-
opts.on("--
|
|
19
|
-
options[:quick] = true
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
opts.on("--logfile", "Set the logfile (defaults to /var/log/enzyme.log)") do |path|
|
|
28
|
+
opts.on("--logfile", "Set the logfile (default: #{defaults[:logfile]})") do |path|
|
|
23
29
|
options[:logfile] = path
|
|
24
30
|
end
|
|
25
31
|
|
|
26
|
-
opts.on("--config CONFIG", "Use config file") do |config|
|
|
32
|
+
opts.on("--config CONFIG", "Use config file (default: #{defaults[:config]})") do |config|
|
|
27
33
|
options[:config] = config
|
|
28
34
|
end
|
|
29
35
|
|
|
30
|
-
opts.on("--
|
|
31
|
-
options[:
|
|
36
|
+
opts.on("--cookbooks PATH", "Use the given path for retrieving and using the cookbooks (default: #{defaults[:base_path]}") do |path|
|
|
37
|
+
options[:base_path] = path
|
|
32
38
|
end
|
|
33
39
|
|
|
34
|
-
opts.on("--
|
|
35
|
-
options[:
|
|
40
|
+
opts.on("--chef-bin PATH", "Use this chef-solo executable to run recipes") do |binary|
|
|
41
|
+
options[:chef_bin] = binary
|
|
36
42
|
end
|
|
37
43
|
|
|
38
|
-
opts.on("--
|
|
39
|
-
options[:
|
|
44
|
+
opts.on("--run-list RECIPES", "Comma-separated list of recipes to run") do |recipe_list|
|
|
45
|
+
options[:run_list] = recipe_list.split(',').collect {|r| "recipe[#{r}]" }
|
|
40
46
|
end
|
|
41
47
|
|
|
42
48
|
opts.on("--report message", "Report a status") do |message|
|
|
43
|
-
options[:
|
|
49
|
+
options[:mode] = :report
|
|
44
50
|
options[:message] = message
|
|
45
51
|
end
|
|
52
|
+
|
|
53
|
+
opts.on("--no-custom", "Do not overlay custom recipes") do
|
|
54
|
+
options[:run_custom] = false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
opts.on("--cached", "Used the cached version of the cookbooks and dna.json") do
|
|
58
|
+
options[:download] = false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
opts.on("--refresh-dna", "Write new dna even if --cached is on") do
|
|
62
|
+
options[:refresh_dna] = true
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
opts.on("--verbose", "Show debug logs as well") do
|
|
66
|
+
options[:log_level] = :debug
|
|
67
|
+
end
|
|
46
68
|
end
|
|
47
69
|
|
|
48
70
|
opts.parse!(args)
|
|
@@ -50,43 +72,57 @@ module EY::Enzyme
|
|
|
50
72
|
config = options[:config] || defaults[:config]
|
|
51
73
|
cli = new(defaults.merge(YAML.load_file(config)).merge(options))
|
|
52
74
|
|
|
53
|
-
if options[:report
|
|
75
|
+
if options[:mode] == :report
|
|
54
76
|
cli.report(options[:message])
|
|
55
|
-
elsif options[:type]
|
|
56
|
-
cli.deploy
|
|
57
77
|
else
|
|
58
|
-
|
|
78
|
+
cli.deploy
|
|
59
79
|
end
|
|
60
80
|
|
|
61
|
-
|
|
62
81
|
rescue OptionParser::InvalidOption
|
|
63
82
|
$stderr.puts "#{File.basename($0)} #{$!.message}"
|
|
64
83
|
abort opts.to_s
|
|
84
|
+
|
|
65
85
|
rescue *IGNORABLE_EXCEPTIONS
|
|
66
86
|
raise
|
|
87
|
+
|
|
67
88
|
rescue DeployError
|
|
68
89
|
if cli
|
|
90
|
+
cli.report $!.message
|
|
69
91
|
cli.notify_user_error($!)
|
|
70
92
|
exit 0
|
|
71
93
|
end
|
|
72
94
|
raise
|
|
95
|
+
|
|
96
|
+
rescue DNAError
|
|
97
|
+
if cli
|
|
98
|
+
cli.report $!.message
|
|
99
|
+
cli.notify_system_error($!)
|
|
100
|
+
exit 0
|
|
101
|
+
end
|
|
102
|
+
raise
|
|
103
|
+
|
|
73
104
|
rescue Exception
|
|
74
105
|
if cli
|
|
75
106
|
cli.notify_system_error($!)
|
|
76
107
|
exit 0
|
|
77
108
|
end
|
|
78
109
|
raise
|
|
110
|
+
|
|
79
111
|
end
|
|
80
112
|
|
|
81
113
|
def initialize(opts={})
|
|
82
114
|
@opts = opts
|
|
83
|
-
@
|
|
84
|
-
@
|
|
115
|
+
@logger = opts[:logger] = MultiLogger.new(opts[:logfile])
|
|
116
|
+
@api = API
|
|
117
|
+
@api.configure(opts[:api], opts[:instance_id], opts[:token], opts[:logger])
|
|
118
|
+
|
|
119
|
+
@logger.level = opts[:log_level]
|
|
85
120
|
|
|
86
121
|
@opts[:timestamp] = Time.now.strftime("%Y-%m-%dT%H-%M-%S")
|
|
87
122
|
end
|
|
88
123
|
|
|
89
124
|
def report(message)
|
|
125
|
+
@logger.debug "REPORT MESSAGE: #{message}"
|
|
90
126
|
@api.report(message)
|
|
91
127
|
end
|
|
92
128
|
|
|
@@ -98,58 +134,96 @@ module EY::Enzyme
|
|
|
98
134
|
@api.notify_error("user", error)
|
|
99
135
|
end
|
|
100
136
|
|
|
101
|
-
MAIN_RECIPE_PATH = '/etc/chef/recipes'
|
|
102
|
-
CUSTOM_RECIPE_PATH = '/etc/chef-custom/recipes'
|
|
103
|
-
|
|
104
137
|
def deploy
|
|
105
138
|
@logger.info "Starting configuration run"
|
|
106
139
|
|
|
140
|
+
ensure_resolv_conf_is_functional
|
|
107
141
|
update_dna
|
|
108
142
|
|
|
109
|
-
|
|
110
|
-
when :main
|
|
111
|
-
run_main
|
|
112
|
-
run_custom
|
|
113
|
-
when :custom
|
|
114
|
-
run_custom
|
|
115
|
-
else
|
|
116
|
-
raise "Unknown type: #{@opts[:type].inspect}"
|
|
117
|
-
end
|
|
118
|
-
|
|
143
|
+
run_cookbooks
|
|
119
144
|
@api.notify_success
|
|
120
145
|
end
|
|
121
146
|
|
|
122
|
-
def
|
|
123
|
-
|
|
124
|
-
|
|
147
|
+
def cookbook_set
|
|
148
|
+
CookbookSet.new(@api, @opts)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private
|
|
152
|
+
|
|
153
|
+
def run_cookbooks
|
|
154
|
+
report "Initializing cookbook run"
|
|
155
|
+
cookbook_set.run
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
## Resovlve resolv.conf stuff
|
|
159
|
+
|
|
160
|
+
def ensure_resolv_conf_is_functional
|
|
161
|
+
@logger.info "Checking resolv.conf"
|
|
162
|
+
unless does_hostname_resolve?
|
|
163
|
+
modify_resolv_conf
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def resolv_conf
|
|
168
|
+
File.read('/etc/resolv.conf')
|
|
125
169
|
end
|
|
126
170
|
|
|
127
|
-
def
|
|
128
|
-
|
|
129
|
-
|
|
171
|
+
def does_hostname_resolve?
|
|
172
|
+
hostname = `/bin/hostname --fqdn 2>/dev/null`
|
|
173
|
+
! hostname.empty?
|
|
130
174
|
end
|
|
131
175
|
|
|
132
|
-
def
|
|
133
|
-
|
|
176
|
+
def add_to_search(path, term)
|
|
177
|
+
data = File.read(path)
|
|
178
|
+
new_data = data.gsub(/^\s*(search\s+.*)$/) do |match|
|
|
179
|
+
if match =~ /\b#{term}\b/
|
|
180
|
+
match
|
|
181
|
+
else
|
|
182
|
+
# only actually append the term to the search line if it's not already there.
|
|
183
|
+
@logger.info "Adding #{term} to the #{path} 'search' line"
|
|
184
|
+
"#{match} #{term}"
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
File.open(path,'w') {|fh| fh.write new_data}
|
|
134
188
|
end
|
|
135
189
|
|
|
136
|
-
def
|
|
137
|
-
|
|
138
|
-
|
|
190
|
+
def modify_resolv_conf
|
|
191
|
+
original_resolv_conf = resolv_conf
|
|
192
|
+
|
|
193
|
+
add_to_search('/etc/resolv.conf','compute-1.internal')
|
|
194
|
+
|
|
195
|
+
if does_hostname_resolve?
|
|
196
|
+
# if it works, make it survive a dhcp lease renewal
|
|
197
|
+
add_to_search('/etc/resolv.conf.head', 'compute-1.internal')
|
|
198
|
+
else
|
|
199
|
+
@logger.info "Change failed; still can't resolve hostname. Reverting change."
|
|
200
|
+
File.open('/etc/resolv.conf','w') {|fh| fh.write original_resolv_conf}
|
|
201
|
+
end
|
|
139
202
|
end
|
|
140
203
|
|
|
204
|
+
### DNA.json manipulation
|
|
205
|
+
|
|
141
206
|
def update_dna
|
|
142
|
-
|
|
207
|
+
FileUtils.mkdir_p @opts[:base_path]
|
|
208
|
+
file = File.join(@opts[:base_path],'dna.json')
|
|
143
209
|
|
|
144
|
-
|
|
145
|
-
|
|
210
|
+
if File.exists?(file) and not @opts[:refresh_dna] and not @opts[:download]
|
|
211
|
+
@logger.info "Skipping download of fresh DNA - using existing #{@chef_dna} file."
|
|
212
|
+
return
|
|
146
213
|
end
|
|
147
214
|
|
|
148
|
-
|
|
215
|
+
report "Fetching instance DNA"
|
|
216
|
+
raise DNAError, "Failed to fetch DNA" unless json = @api.dna
|
|
149
217
|
|
|
150
|
-
|
|
218
|
+
main_json = {}
|
|
219
|
+
main_json['run_list'] = @opts[:run_list]
|
|
220
|
+
main_json['dna'] = json.dup
|
|
221
|
+
save_dna(file,main_json)
|
|
222
|
+
end
|
|
151
223
|
|
|
152
|
-
|
|
224
|
+
def save_dna(file, json)
|
|
225
|
+
@logger.debug "Writing json dna to #{file}"
|
|
226
|
+
File.open(file, 'w') do |f|
|
|
153
227
|
f.puts JSON.pretty_generate(json)
|
|
154
228
|
f.chmod(0600)
|
|
155
229
|
end
|
|
@@ -1,95 +1,175 @@
|
|
|
1
1
|
module EY::Enzyme
|
|
2
2
|
class CookbookSet
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@
|
|
6
|
-
@
|
|
7
|
-
@
|
|
8
|
-
@
|
|
9
|
-
@
|
|
10
|
-
@
|
|
11
|
-
@
|
|
3
|
+
|
|
4
|
+
def initialize(api, opts)
|
|
5
|
+
@opts = opts
|
|
6
|
+
@api = api
|
|
7
|
+
@chef_config = File.join(opts[:base_path], "solo.rb")
|
|
8
|
+
@chef_dna = File.join(opts[:base_path], "dna.json")
|
|
9
|
+
@recipes_path = File.join(opts[:base_path], "recipes")
|
|
10
|
+
@main_recipes_url = opts[:recipes_url]
|
|
11
|
+
@user_recipes_url = opts.has_key?(:custom_recipes_url) ? opts[:custom_recipes_url] : api.custom_recipe_url
|
|
12
|
+
@logger = opts[:logger]
|
|
13
|
+
@timestamp = Time.now.strftime("%Y-%m-%dT%H-%M-%S")
|
|
14
|
+
@chef_log = "/var/log/chef.#{@timestamp}.log"
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
def run
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
if @main_recipes_url
|
|
19
|
+
setup
|
|
20
|
+
execute
|
|
21
|
+
else
|
|
22
|
+
@logger.info "No recipes for chef run. Skipping"
|
|
18
23
|
end
|
|
19
|
-
|
|
20
|
-
setup
|
|
21
|
-
execute
|
|
22
24
|
ensure
|
|
23
25
|
upload
|
|
24
26
|
end
|
|
25
27
|
|
|
28
|
+
private
|
|
29
|
+
|
|
26
30
|
def setup
|
|
27
|
-
@logger.info "Starting
|
|
31
|
+
@logger.info "Starting chef run"
|
|
28
32
|
|
|
29
33
|
abort("Instance ID mismatch") unless instance_id_valid?
|
|
30
34
|
FileUtils.rm(@chef_log) if File.exist?(@chef_log)
|
|
31
35
|
|
|
32
|
-
|
|
36
|
+
# Create the EC2 hint for ohai
|
|
37
|
+
# See: https://geekblood.wordpress.com/2015/03/13/enabling-ec2-metadata-in-ohai/
|
|
38
|
+
FileUtils.mkdir_p("#{@opts[:base_path]}/ohai/hints/")
|
|
39
|
+
FileUtils.touch("#{@opts[:base_path]}/ohai/hints/ec2.json")
|
|
33
40
|
|
|
34
|
-
File.open(chef_config, "w") do |f|
|
|
41
|
+
File.open(@chef_config, "w") do |f|
|
|
35
42
|
f.puts <<-EOS
|
|
36
43
|
cookbook_path "#{@recipes_path}/cookbooks"
|
|
37
44
|
file_store_path "#{@recipes_path}/"
|
|
38
45
|
file_cache_path "#{@recipes_path}/"
|
|
46
|
+
data_bag_path "#{@recipes_path}/data_bags"
|
|
39
47
|
log_location "#{@chef_log}"
|
|
40
48
|
log_level :info
|
|
41
49
|
node_name "#{@opts[:instance_id]}"
|
|
42
50
|
EOS
|
|
43
51
|
end
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
if @opts[:download]
|
|
54
|
+
@logger.info "Removing cookbooks"
|
|
55
|
+
FileUtils.rm_rf(@recipes_path)
|
|
56
|
+
FileUtils.mkdir_p(@recipes_path)
|
|
57
|
+
|
|
58
|
+
@logger.info "Downloading main cookbooks"
|
|
59
|
+
download_cookbooks
|
|
60
|
+
|
|
61
|
+
unless @user_recipes_url.nil?
|
|
62
|
+
if @opts[:run_custom]
|
|
63
|
+
@logger.info "Overlaying custom user cookbook recipes"
|
|
64
|
+
overlay_custom_cookbooks
|
|
65
|
+
else
|
|
66
|
+
@logger.info "Skipping overlay of custom cookbook recipes"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
@logger.info "Skipping download of new cookbooks - using existing cookbooks in #{@recipes_path}"
|
|
71
|
+
end
|
|
72
|
+
end
|
|
46
73
|
|
|
47
|
-
|
|
74
|
+
def download_cookbooks
|
|
48
75
|
FileUtils.mkdir_p(@recipes_path)
|
|
76
|
+
result = %x[cd #{@recipes_path} && curl -fs '#{@main_recipes_url}' | tar -zxv]
|
|
77
|
+
if $?.exitstatus > 0
|
|
78
|
+
@logger.error "Failed to download and untar main cookbook."
|
|
79
|
+
@logger.error "Error output: #{result}"
|
|
80
|
+
raise DeployError, "Main cookbook download failed."
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def overlay_custom_cookbooks
|
|
85
|
+
Dir.mktmpdir do |tmpdir|
|
|
86
|
+
file=File.join(tmpdir,'user_recipes.tgz')
|
|
87
|
+
result = %x[curl -fs '#{@user_recipes_url}' -o #{file}]
|
|
88
|
+
if $?.exitstatus > 0
|
|
89
|
+
@logger.error "Failed to download user cookbook from #{@user_recipes_url}"
|
|
90
|
+
raise DeployError, "User cookbook download failed."
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
#Check COMPATIBILITY.txt file for release compatibilities
|
|
94
|
+
compat = %x[tar -azxf '#{file}' COMPATIBILITY.txt 2>/dev/null]
|
|
95
|
+
if $?.exitstatus == 0
|
|
96
|
+
# TODO: Determine how to compare against opts[:release_label]
|
|
97
|
+
# if not compatibible, log it, and raise DeployError, "Incompatible user cookbook found."
|
|
98
|
+
else
|
|
99
|
+
@api.report "WARNING: No COMPATIBILITY.txt file found in user cookbook."
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
result = %x[cd #{@recipes_path} && tar -zxvf #{file}]
|
|
103
|
+
if $?.exitstatus > 0
|
|
104
|
+
@logger.error "Failed to overlay user cookbook over main cookbook."
|
|
105
|
+
@logger.error "Error output: #{result}"
|
|
106
|
+
raise DeployError, "User cookbook overlay failed."
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
end
|
|
49
110
|
end
|
|
50
111
|
|
|
51
112
|
def execute
|
|
52
|
-
|
|
113
|
+
# Remove any stacktrace file from previous runs
|
|
114
|
+
stacktrace_file = File.join(@recipes_path,"chef-stacktrace.out")
|
|
115
|
+
FileUtils.rm_f stacktrace_file
|
|
116
|
+
tail = nil
|
|
117
|
+
if @logger.debug?
|
|
118
|
+
system("touch #{@chef_log}")
|
|
119
|
+
tail = Thread.new do
|
|
120
|
+
File.open(@chef_log, "r") do |fp|
|
|
121
|
+
while true do
|
|
122
|
+
select([fp])
|
|
123
|
+
$stderr << fp.read
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
command = "#{@opts[:chef_bin]} -j #{@chef_dna} -c #{@chef_config} > #{@chef_log} 2>&1"
|
|
53
129
|
@logger.debug "Running: #{command}"
|
|
54
130
|
if system(command)
|
|
55
131
|
@logger.info "Running telinit"
|
|
56
132
|
system("telinit q")
|
|
57
|
-
@logger.info "Finished
|
|
133
|
+
@logger.info "Finished chef run"
|
|
58
134
|
else
|
|
59
|
-
@logger.error("
|
|
60
|
-
@logger.error("
|
|
61
|
-
raise DeployError, "
|
|
135
|
+
@logger.error("Chef run failed. Reporting error")
|
|
136
|
+
@logger.error("Error output: #{chef_error_from_log}")
|
|
137
|
+
raise DeployError, "Chef run failed - see log file"
|
|
62
138
|
end
|
|
63
139
|
ensure
|
|
64
140
|
if File.exists?(@chef_log)
|
|
65
|
-
|
|
141
|
+
if File.exists?(stacktrace_file)
|
|
142
|
+
st_contents = File.read(stacktrace_file)
|
|
143
|
+
File.open(@chef_log, "a") do |l|
|
|
144
|
+
l.puts "\n-----------"
|
|
145
|
+
l.puts "Stack Trace (from #{stacktrace_file})"
|
|
146
|
+
l.puts "-----------\n\n#{st_contents}"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
FileUtils.ln_sf(@chef_log, "/var/log/chef.log")
|
|
66
150
|
end
|
|
151
|
+
tail && tail.kill
|
|
67
152
|
end
|
|
68
153
|
|
|
69
154
|
def upload
|
|
70
155
|
return unless File.exist?(@chef_log)
|
|
71
156
|
|
|
72
157
|
file = "#{@chef_log}.#{rand(1000)}.gz"
|
|
73
|
-
Zlib::GzipWriter.open(file)
|
|
158
|
+
Zlib::GzipWriter.open(file) do |io|
|
|
159
|
+
io << File.read(@chef_log)
|
|
160
|
+
end
|
|
74
161
|
|
|
75
|
-
unless @api.upload(
|
|
76
|
-
@logger.error "Failed to upload
|
|
77
|
-
raise UploadError, "
|
|
162
|
+
unless @api.upload('main', File.new(file))
|
|
163
|
+
@logger.error "Failed to upload chef log. Reporting error"
|
|
164
|
+
raise UploadError, "Failed to upload chef log"
|
|
78
165
|
end
|
|
79
166
|
rescue UploadError => error
|
|
167
|
+
@api.report error.message
|
|
80
168
|
@api.notify_error("logupload", error)
|
|
81
169
|
ensure
|
|
82
170
|
FileUtils.rm_f(file) if file
|
|
83
171
|
end
|
|
84
172
|
|
|
85
|
-
def main?
|
|
86
|
-
@name == "main"
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def chef_config
|
|
90
|
-
main? ? "/etc/chef/solo.rb" : "/etc/chef-custom/solo.rb"
|
|
91
|
-
end
|
|
92
|
-
|
|
93
173
|
def chef_error_from_log
|
|
94
174
|
unless File.exist?(@chef_log)
|
|
95
175
|
return "(log doesn't exist)"
|
|
@@ -118,7 +198,9 @@ module EY::Enzyme
|
|
|
118
198
|
end
|
|
119
199
|
|
|
120
200
|
def local_instance_id
|
|
121
|
-
@local_instance_id ||= open(
|
|
201
|
+
@local_instance_id ||= URI.open("http://169.254.169.254/latest/meta-data/instance-id",
|
|
202
|
+
&:read)
|
|
122
203
|
end
|
|
204
|
+
|
|
123
205
|
end
|
|
124
206
|
end
|
|
@@ -1,11 +1,30 @@
|
|
|
1
1
|
module EY::Enzyme
|
|
2
2
|
class MultiLogger
|
|
3
3
|
|
|
4
|
+
SEVERITIES = {
|
|
5
|
+
:fatal => Logger::FATAL,
|
|
6
|
+
:error => Logger::ERROR,
|
|
7
|
+
:warn => Logger::WARN,
|
|
8
|
+
:info => Logger::INFO,
|
|
9
|
+
:debug => Logger::DEBUG,
|
|
10
|
+
}
|
|
11
|
+
|
|
4
12
|
def initialize(log_file)
|
|
5
13
|
@enzyme_log = Logger.new(log_file)
|
|
6
14
|
@stderr_log = Logger.new($stderr)
|
|
7
15
|
end
|
|
8
16
|
|
|
17
|
+
def level=(level)
|
|
18
|
+
@level = level
|
|
19
|
+
raise "Invalid log level: #{level}" unless SEVERITIES[level]
|
|
20
|
+
@enzyme_log.level = SEVERITIES[:debug]
|
|
21
|
+
@stderr_log.level = SEVERITIES[level]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def debug?
|
|
25
|
+
@level == :debug
|
|
26
|
+
end
|
|
27
|
+
|
|
9
28
|
def debug(message)
|
|
10
29
|
log(:debug, message)
|
|
11
30
|
end
|
data/lib/ey_enzyme/version.rb
CHANGED
data/lib/ey_enzyme.rb
CHANGED
|
@@ -3,18 +3,16 @@ require "open-uri"
|
|
|
3
3
|
require "zlib"
|
|
4
4
|
require "logger"
|
|
5
5
|
require "optparse"
|
|
6
|
+
require "fileutils"
|
|
6
7
|
|
|
7
8
|
require 'json'
|
|
8
9
|
require 'restclient'
|
|
9
|
-
require 'chef'
|
|
10
|
-
require 'chef/client'
|
|
11
10
|
|
|
12
11
|
module EY; end
|
|
12
|
+
require "ey_enzyme/api"
|
|
13
13
|
|
|
14
14
|
require "ey_enzyme/multi_logger"
|
|
15
|
-
require "ey_enzyme/api"
|
|
16
15
|
require "ey_enzyme/cli"
|
|
17
|
-
require "ey_enzyme/old_cli"
|
|
18
16
|
require "ey_enzyme/cookbook_set"
|
|
19
17
|
require "ey_enzyme/version"
|
|
20
18
|
|
metadata
CHANGED
|
@@ -1,193 +1,161 @@
|
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ey_enzyme
|
|
3
|
-
version: !ruby/object:Gem::Version
|
|
4
|
-
|
|
5
|
-
prerelease:
|
|
6
|
-
segments:
|
|
7
|
-
- 0
|
|
8
|
-
- 9
|
|
9
|
-
- 44
|
|
10
|
-
version: 0.9.44
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 2.0.7
|
|
11
5
|
platform: ruby
|
|
12
|
-
authors:
|
|
6
|
+
authors:
|
|
13
7
|
- Engine Yard Inc.
|
|
14
8
|
autorequire:
|
|
15
9
|
bindir: bin
|
|
16
10
|
cert_chain: []
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
- !ruby/object:Gem::Dependency
|
|
11
|
+
date: 2021-12-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
21
14
|
name: json
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 2.6.1
|
|
26
20
|
- - ">="
|
|
27
|
-
- !ruby/object:Gem::Version
|
|
28
|
-
|
|
29
|
-
segments:
|
|
30
|
-
- 0
|
|
31
|
-
version: "0"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 2.6.0
|
|
32
23
|
type: :runtime
|
|
33
|
-
version_requirements: *id001
|
|
34
|
-
- !ruby/object:Gem::Dependency
|
|
35
|
-
name: rest-client
|
|
36
24
|
prerelease: false
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - "~>"
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 2.6.1
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 2.6.0
|
|
33
|
+
- !ruby/object:Gem::Dependency
|
|
34
|
+
name: mime-types
|
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 3.3.1
|
|
48
40
|
type: :runtime
|
|
49
|
-
version_requirements: *id002
|
|
50
|
-
- !ruby/object:Gem::Dependency
|
|
51
|
-
name: chef
|
|
52
41
|
prerelease: false
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
version:
|
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 3.3.1
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: rest-client
|
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.1'
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 2.1.0
|
|
65
57
|
type: :runtime
|
|
66
|
-
version_requirements: *id003
|
|
67
|
-
- !ruby/object:Gem::Dependency
|
|
68
|
-
name: chef-deploy
|
|
69
58
|
prerelease: false
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- 5
|
|
80
|
-
version: 0.2.5
|
|
81
|
-
type: :runtime
|
|
82
|
-
version_requirements: *id004
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - "~>"
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '2.1'
|
|
64
|
+
- - ">="
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: 2.1.0
|
|
67
|
+
- !ruby/object:Gem::Dependency
|
|
84
68
|
name: rake
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
none: false
|
|
88
|
-
requirements:
|
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
89
71
|
- - ">="
|
|
90
|
-
- !ruby/object:Gem::Version
|
|
91
|
-
|
|
92
|
-
segments:
|
|
93
|
-
- 0
|
|
94
|
-
version: "0"
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
95
74
|
type: :development
|
|
96
|
-
version_requirements: *id005
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: rspec
|
|
99
75
|
prerelease: false
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - ">="
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '0'
|
|
81
|
+
- !ruby/object:Gem::Dependency
|
|
82
|
+
name: rspec
|
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - "~>"
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '2.14'
|
|
110
88
|
type: :development
|
|
111
|
-
version_requirements: *id006
|
|
112
|
-
- !ruby/object:Gem::Dependency
|
|
113
|
-
name: fakeweb
|
|
114
89
|
prerelease: false
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - "~>"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '2.14'
|
|
95
|
+
- !ruby/object:Gem::Dependency
|
|
96
|
+
name: fakeweb
|
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
118
99
|
- - ">="
|
|
119
|
-
- !ruby/object:Gem::Version
|
|
120
|
-
|
|
121
|
-
segments:
|
|
122
|
-
- 0
|
|
123
|
-
version: "0"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0'
|
|
124
102
|
type: :development
|
|
125
|
-
version_requirements: *id007
|
|
126
|
-
- !ruby/object:Gem::Dependency
|
|
127
|
-
name: fakeweb-matcher
|
|
128
103
|
prerelease: false
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
requirements:
|
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
132
106
|
- - ">="
|
|
133
|
-
- !ruby/object:Gem::Version
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '0'
|
|
109
|
+
- !ruby/object:Gem::Dependency
|
|
110
|
+
name: fakeweb-matcher
|
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - ">="
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: '0'
|
|
138
116
|
type: :development
|
|
139
|
-
|
|
117
|
+
prerelease: false
|
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '0'
|
|
140
123
|
description: Gem for kicking off chef recipes
|
|
141
124
|
email: ninja@engineyard.com
|
|
142
|
-
executables:
|
|
125
|
+
executables:
|
|
143
126
|
- ey-enzyme
|
|
144
|
-
- ey-recipes
|
|
145
127
|
extensions: []
|
|
146
|
-
|
|
147
128
|
extra_rdoc_files: []
|
|
148
|
-
|
|
149
|
-
|
|
129
|
+
files:
|
|
130
|
+
- bin/ey-enzyme
|
|
131
|
+
- lib/ey_enzyme.rb
|
|
150
132
|
- lib/ey_enzyme/api.rb
|
|
133
|
+
- lib/ey_enzyme/api/client.rb
|
|
151
134
|
- lib/ey_enzyme/cli.rb
|
|
152
135
|
- lib/ey_enzyme/cookbook_set.rb
|
|
153
136
|
- lib/ey_enzyme/multi_logger.rb
|
|
154
|
-
- lib/ey_enzyme/old_cli.rb
|
|
155
137
|
- lib/ey_enzyme/version.rb
|
|
156
|
-
|
|
157
|
-
- bin/ey-enzyme
|
|
158
|
-
- bin/ey-recipes
|
|
159
|
-
homepage: http://github.com/engineyard/ey_enzyme
|
|
138
|
+
homepage: https://github.com/engineyard/ey_enzyme
|
|
160
139
|
licenses: []
|
|
161
|
-
|
|
140
|
+
metadata: {}
|
|
162
141
|
post_install_message:
|
|
163
142
|
rdoc_options: []
|
|
164
|
-
|
|
165
|
-
require_paths:
|
|
143
|
+
require_paths:
|
|
166
144
|
- lib
|
|
167
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
|
168
|
-
|
|
169
|
-
requirements:
|
|
145
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
|
+
requirements:
|
|
170
147
|
- - ">="
|
|
171
|
-
- !ruby/object:Gem::Version
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
version: "0"
|
|
176
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
177
|
-
none: false
|
|
178
|
-
requirements:
|
|
148
|
+
- !ruby/object:Gem::Version
|
|
149
|
+
version: '0'
|
|
150
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
|
+
requirements:
|
|
179
152
|
- - ">="
|
|
180
|
-
- !ruby/object:Gem::Version
|
|
181
|
-
|
|
182
|
-
segments:
|
|
183
|
-
- 0
|
|
184
|
-
version: "0"
|
|
153
|
+
- !ruby/object:Gem::Version
|
|
154
|
+
version: '0'
|
|
185
155
|
requirements: []
|
|
186
|
-
|
|
187
156
|
rubyforge_project:
|
|
188
|
-
rubygems_version:
|
|
157
|
+
rubygems_version: 2.6.14
|
|
189
158
|
signing_key:
|
|
190
|
-
specification_version:
|
|
159
|
+
specification_version: 4
|
|
191
160
|
summary: Gem for kicking off chef recipes
|
|
192
161
|
test_files: []
|
|
193
|
-
|
data/bin/ey-recipes
DELETED
data/lib/ey_enzyme/old_cli.rb
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
module EY::Enzyme
|
|
2
|
-
class OldCLI
|
|
3
|
-
def self.run(args)
|
|
4
|
-
new_args = []
|
|
5
|
-
|
|
6
|
-
opts = OptionParser.new do |opts|
|
|
7
|
-
opts.version = "0.0.1"
|
|
8
|
-
|
|
9
|
-
opts.banner = "Usage: ey-recipes[-flag] [argument]"
|
|
10
|
-
opts.define_head "ey-recipes: running recipes..."
|
|
11
|
-
opts.separator '*'*80
|
|
12
|
-
|
|
13
|
-
opts.on("-c CONFIG", "--config CONFIG", "Use config file") do |config|
|
|
14
|
-
# NO-OP
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
opts.on("--deploy-main ENV", "Run main recipes") do |env_name|
|
|
18
|
-
new_args << "--main"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
opts.on("-d ENV", "--deploy ENV", "Run custom recipes") do |env_name|
|
|
22
|
-
new_args << "--custom"
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
opts.parse!(args)
|
|
27
|
-
|
|
28
|
-
if new_args.any?
|
|
29
|
-
CLI.run(new_args)
|
|
30
|
-
else
|
|
31
|
-
$stderr.puts opts
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|