engineyard 1.4.29 → 1.7.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +139 -4
- data/bin/ey +1 -7
- data/lib/engineyard.rb +1 -22
- data/lib/engineyard/cli.rb +192 -94
- data/lib/engineyard/cli/#recipes.rb# +32 -0
- data/lib/engineyard/cli/api.rb +42 -28
- data/lib/engineyard/cli/recipes.rb +13 -6
- data/lib/engineyard/cli/ui.rb +103 -42
- data/lib/engineyard/cli/web.rb +16 -10
- data/lib/engineyard/config.rb +92 -18
- data/lib/engineyard/deploy_config.rb +66 -0
- data/lib/engineyard/deploy_config/migrate.rb +125 -0
- data/lib/engineyard/deploy_config/ref.rb +56 -0
- data/lib/engineyard/error.rb +38 -78
- data/lib/engineyard/repo.rb +75 -27
- data/lib/engineyard/serverside_runner.rb +133 -0
- data/lib/engineyard/thor.rb +110 -18
- data/lib/engineyard/version.rb +1 -1
- data/spec/engineyard/cli/api_spec.rb +10 -16
- data/spec/engineyard/cli_spec.rb +0 -11
- data/spec/engineyard/config_spec.rb +1 -8
- data/spec/engineyard/deploy_config_spec.rb +203 -0
- data/spec/engineyard/eyrc_spec.rb +2 -0
- data/spec/engineyard/repo_spec.rb +57 -34
- data/spec/ey/deploy_spec.rb +102 -52
- data/spec/ey/list_environments_spec.rb +69 -14
- data/spec/ey/login_spec.rb +11 -7
- data/spec/ey/logout_spec.rb +4 -4
- data/spec/ey/logs_spec.rb +6 -6
- data/spec/ey/recipes/apply_spec.rb +1 -1
- data/spec/ey/recipes/download_spec.rb +1 -1
- data/spec/ey/recipes/upload_spec.rb +6 -6
- data/spec/ey/rollback_spec.rb +3 -3
- data/spec/ey/ssh_spec.rb +9 -9
- data/spec/ey/status_spec.rb +2 -2
- data/spec/ey/whoami_spec.rb +9 -8
- data/spec/spec_helper.rb +18 -15
- data/spec/support/{fake_awsm.rb → git_repos.rb} +0 -14
- data/spec/support/helpers.rb +84 -28
- data/spec/support/matchers.rb +0 -16
- data/spec/support/shared_behavior.rb +83 -103
- metadata +65 -51
- data/lib/engineyard/api.rb +0 -117
- data/lib/engineyard/collection.rb +0 -7
- data/lib/engineyard/collection/abstract.rb +0 -71
- data/lib/engineyard/collection/apps.rb +0 -8
- data/lib/engineyard/collection/environments.rb +0 -8
- data/lib/engineyard/model.rb +0 -12
- data/lib/engineyard/model/account.rb +0 -8
- data/lib/engineyard/model/api_struct.rb +0 -33
- data/lib/engineyard/model/app.rb +0 -32
- data/lib/engineyard/model/deployment.rb +0 -90
- data/lib/engineyard/model/environment.rb +0 -194
- data/lib/engineyard/model/instance.rb +0 -166
- data/lib/engineyard/model/log.rb +0 -9
- data/lib/engineyard/model/user.rb +0 -6
- data/lib/engineyard/resolver.rb +0 -134
- data/lib/engineyard/rest_client_ext.rb +0 -9
- data/lib/engineyard/ruby_ext.rb +0 -9
- data/spec/engineyard/api_spec.rb +0 -39
- data/spec/engineyard/collection/apps_spec.rb +0 -16
- data/spec/engineyard/collection/environments_spec.rb +0 -16
- data/spec/engineyard/model/api_struct_spec.rb +0 -41
- data/spec/engineyard/model/environment_spec.rb +0 -198
- data/spec/engineyard/model/instance_spec.rb +0 -27
- data/spec/engineyard/resolver_spec.rb +0 -112
- data/spec/support/fake_awsm.ru +0 -245
- data/spec/support/scenarios.rb +0 -417
@@ -1,33 +0,0 @@
|
|
1
|
-
module EY
|
2
|
-
module Model
|
3
|
-
class ApiStruct < Struct
|
4
|
-
|
5
|
-
def self.new(*args, &block)
|
6
|
-
super(*args) do |*block_args|
|
7
|
-
block.call(*block_args) if block
|
8
|
-
|
9
|
-
def self.from_array(array, common_values = {})
|
10
|
-
array.map do |values|
|
11
|
-
from_hash(values.merge(common_values))
|
12
|
-
end if array
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.from_hash(hash)
|
16
|
-
return nil unless hash
|
17
|
-
# in ruby 1.8, #members is an array of strings
|
18
|
-
# in ruby 1.9, #members is an array of symbols
|
19
|
-
members = new.members.map {|m| m.to_sym}
|
20
|
-
values = members.map{|a| hash.has_key?(a) ? hash[a] : hash[a.to_s] }
|
21
|
-
new(*values)
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
def api_get(uri, options = {})
|
28
|
-
api.request(uri, options.merge(:method => :get))
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/engineyard/model/app.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
module EY
|
2
|
-
module Model
|
3
|
-
class App < ApiStruct.new(:id, :account, :name, :repository_uri, :environments, :api)
|
4
|
-
|
5
|
-
def self.from_hash(hash)
|
6
|
-
super.tap do |app|
|
7
|
-
app.environments = Environment.from_array(app.environments, :api => app.api)
|
8
|
-
app.account = Account.from_hash(app.account)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.from_array(*)
|
13
|
-
Collection::Apps.new(super)
|
14
|
-
end
|
15
|
-
|
16
|
-
def sole_environment
|
17
|
-
if environments.size == 1
|
18
|
-
environments.first
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def sole_environment!
|
23
|
-
sole_environment or raise NoSingleEnvironmentError.new(self)
|
24
|
-
end
|
25
|
-
|
26
|
-
def last_deployment_on(environment)
|
27
|
-
Deployment.last(self, environment, api)
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
require 'escape'
|
2
|
-
|
3
|
-
module EY
|
4
|
-
module Model
|
5
|
-
class Deployment < ApiStruct.new(:id, :app, :created_at, :commit, :environment, :finished_at, :migrate_command, :output, :ref, :resolved_ref, :successful, :user_name)
|
6
|
-
def self.api_root(app_id, environment_id)
|
7
|
-
"/apps/#{app_id}/environments/#{environment_id}/deployments"
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.last(app, environment, api)
|
11
|
-
get(app, environment, 'last', api)
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.get(app, environment, id, api)
|
15
|
-
response = api.request(api_root(app.id, environment.id) + "/#{id}", :method => :get)
|
16
|
-
load_from_response app, environment, response
|
17
|
-
rescue EY::API::ResourceNotFound
|
18
|
-
nil
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.load_from_response(app, environment, response)
|
22
|
-
dep = new
|
23
|
-
dep.app = app
|
24
|
-
dep.environment = environment
|
25
|
-
dep.update_with_response(response)
|
26
|
-
dep
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.started(environment, app, ref, migrate_command)
|
30
|
-
deployment = from_hash({
|
31
|
-
:app => app,
|
32
|
-
:environment => environment,
|
33
|
-
:migrate_command => migrate_command,
|
34
|
-
:ref => ref,
|
35
|
-
})
|
36
|
-
deployment.start
|
37
|
-
deployment
|
38
|
-
end
|
39
|
-
|
40
|
-
def migrate
|
41
|
-
!!migrate_command
|
42
|
-
end
|
43
|
-
|
44
|
-
alias successful? successful
|
45
|
-
|
46
|
-
def start
|
47
|
-
post_to_api({
|
48
|
-
:migrate => migrate,
|
49
|
-
:migrate_command => migrate_command,
|
50
|
-
:output => output,
|
51
|
-
:ref => ref,
|
52
|
-
})
|
53
|
-
end
|
54
|
-
|
55
|
-
def finished(successful, output)
|
56
|
-
self.successful = successful
|
57
|
-
self.output = output
|
58
|
-
put_to_api({:successful => successful, :output => output})
|
59
|
-
end
|
60
|
-
|
61
|
-
def update_with_response(response)
|
62
|
-
response['deployment'].each do |key,val|
|
63
|
-
send("#{key}=", val) if respond_to?("#{key}=")
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def post_to_api(params)
|
70
|
-
update_with_response api.request(collection_uri, :method => :post, :params => {:deployment => params})
|
71
|
-
end
|
72
|
-
|
73
|
-
def put_to_api(params)
|
74
|
-
update_with_response api.request(member_uri("/finished"), :method => :put, :params => {:deployment => params})
|
75
|
-
end
|
76
|
-
|
77
|
-
def collection_uri
|
78
|
-
self.class.api_root(app.id, environment.id)
|
79
|
-
end
|
80
|
-
|
81
|
-
def member_uri(path = nil)
|
82
|
-
collection_uri + "/#{id}#{path}"
|
83
|
-
end
|
84
|
-
|
85
|
-
def api
|
86
|
-
app.api
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,194 +0,0 @@
|
|
1
|
-
module EY
|
2
|
-
module Model
|
3
|
-
class Environment < ApiStruct.new(:id, :account, :name, :framework_env, :instances, :instances_count,
|
4
|
-
:apps, :app_master, :username, :app_server_stack_name, :deployment_configurations,
|
5
|
-
:load_balancer_ip_address, :api)
|
6
|
-
require 'launchy'
|
7
|
-
|
8
|
-
attr_accessor :ignore_bad_master
|
9
|
-
|
10
|
-
def self.from_hash(hash)
|
11
|
-
super.tap do |env|
|
12
|
-
env.username = hash['ssh_username']
|
13
|
-
env.apps = App.from_array(env.apps, :api => env.api)
|
14
|
-
env.account = Account.from_hash(env.account)
|
15
|
-
env.instances = Instance.from_array(hash['instances'], :environment => env)
|
16
|
-
env.app_master = Instance.from_hash(env.app_master.merge(:environment => env)) if env.app_master
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.from_array(*)
|
21
|
-
Collection::Environments.new(super)
|
22
|
-
end
|
23
|
-
|
24
|
-
def logs
|
25
|
-
Log.from_array(api_get("/environments/#{id}/logs")["logs"])
|
26
|
-
end
|
27
|
-
|
28
|
-
def app_master!
|
29
|
-
master = app_master
|
30
|
-
if master.nil?
|
31
|
-
raise NoAppMasterError.new(name)
|
32
|
-
elsif !ignore_bad_master && master.status != "running"
|
33
|
-
raise BadAppMasterStatusError.new(master.status)
|
34
|
-
end
|
35
|
-
master
|
36
|
-
end
|
37
|
-
|
38
|
-
def deploy(app, ref, deploy_options={})
|
39
|
-
app_master!.deploy(app,
|
40
|
-
ref,
|
41
|
-
migration_command(app, deploy_options),
|
42
|
-
config.merge(deploy_options['extras']),
|
43
|
-
deploy_options['verbose'])
|
44
|
-
end
|
45
|
-
|
46
|
-
def rollback(app, extra_deploy_hook_options={}, verbose=false)
|
47
|
-
app_master!.rollback(app,
|
48
|
-
config.merge(extra_deploy_hook_options),
|
49
|
-
verbose)
|
50
|
-
end
|
51
|
-
|
52
|
-
def take_down_maintenance_page(app, verbose=false)
|
53
|
-
app_master!.take_down_maintenance_page(app, verbose)
|
54
|
-
end
|
55
|
-
|
56
|
-
def put_up_maintenance_page(app, verbose=false)
|
57
|
-
app_master!.put_up_maintenance_page(app, verbose)
|
58
|
-
end
|
59
|
-
|
60
|
-
def rebuild
|
61
|
-
api.request("/environments/#{id}/update_instances", :method => :put)
|
62
|
-
end
|
63
|
-
|
64
|
-
def run_custom_recipes
|
65
|
-
api.request("/environments/#{id}/run_custom_recipes", :method => :put)
|
66
|
-
end
|
67
|
-
|
68
|
-
def download_recipes
|
69
|
-
if File.exist?('cookbooks')
|
70
|
-
raise EY::Error, "Could not download, cookbooks already exists"
|
71
|
-
end
|
72
|
-
|
73
|
-
require 'tempfile'
|
74
|
-
tmp = Tempfile.new("recipes")
|
75
|
-
tmp.write(api.request("/environments/#{id}/recipes"))
|
76
|
-
tmp.flush
|
77
|
-
tmp.close
|
78
|
-
|
79
|
-
cmd = "tar xzf '#{tmp.path}' cookbooks"
|
80
|
-
|
81
|
-
unless system(cmd)
|
82
|
-
raise EY::Error, "Could not unarchive recipes.\nCommand `#{cmd}` exited with an error."
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def upload_recipes_at_path(recipes_path)
|
87
|
-
recipes_path = Pathname.new(recipes_path)
|
88
|
-
if recipes_path.exist?
|
89
|
-
upload_recipes recipes_path.open('rb')
|
90
|
-
else
|
91
|
-
raise EY::Error, "Recipes file not found: #{recipes_path}"
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def tar_and_upload_recipes_in_cookbooks_dir
|
96
|
-
require 'tempfile'
|
97
|
-
unless File.exist?("cookbooks")
|
98
|
-
raise EY::Error, "Could not find chef recipes. Please run from the root of your recipes repo."
|
99
|
-
end
|
100
|
-
|
101
|
-
recipes_file = Tempfile.new("recipes")
|
102
|
-
cmd = "tar czf '#{recipes_file.path}' cookbooks/"
|
103
|
-
|
104
|
-
unless system(cmd)
|
105
|
-
raise EY::Error, "Could not archive recipes.\nCommand `#{cmd}` exited with an error."
|
106
|
-
end
|
107
|
-
|
108
|
-
upload_recipes(recipes_file)
|
109
|
-
end
|
110
|
-
|
111
|
-
def upload_recipes(file_to_upload)
|
112
|
-
api.request("/environments/#{id}/recipes", {
|
113
|
-
:method => :post,
|
114
|
-
:params => {:file => file_to_upload}
|
115
|
-
})
|
116
|
-
end
|
117
|
-
|
118
|
-
# If force_ref is a string, use it as the ref, otherwise use it as a boolean.
|
119
|
-
def resolve_branch(ref, force_ref=false)
|
120
|
-
if String === force_ref
|
121
|
-
ref, force_ref = force_ref, true
|
122
|
-
end
|
123
|
-
|
124
|
-
if !ref
|
125
|
-
default_branch
|
126
|
-
elsif force_ref || !default_branch || ref == default_branch
|
127
|
-
ref
|
128
|
-
else
|
129
|
-
raise BranchMismatchError.new(default_branch, ref)
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
def configuration
|
134
|
-
EY.config.environments[self.name] || {}
|
135
|
-
end
|
136
|
-
alias_method :config, :configuration
|
137
|
-
|
138
|
-
def default_branch
|
139
|
-
EY.config.default_branch(name)
|
140
|
-
end
|
141
|
-
|
142
|
-
def shorten_name_for(app)
|
143
|
-
name.gsub(/^#{Regexp.quote(app.name)}_/, '')
|
144
|
-
end
|
145
|
-
|
146
|
-
def launch
|
147
|
-
Launchy.open(app_master!.hostname_url)
|
148
|
-
end
|
149
|
-
|
150
|
-
def migration_command(app, deploy_options)
|
151
|
-
# regarding deploy_options['migrate']:
|
152
|
-
#
|
153
|
-
# missing means migrate how the yaml file says to
|
154
|
-
# nil means don't migrate
|
155
|
-
# true means migrate w/custom command (if present) or default
|
156
|
-
# a string means migrate with this specific command
|
157
|
-
return nil if no_migrate?(deploy_options)
|
158
|
-
command = migration_command_from_command_line(deploy_options)
|
159
|
-
unless command
|
160
|
-
return nil if no_migrate?(config)
|
161
|
-
command = migration_command_from_config
|
162
|
-
end
|
163
|
-
command = migration_command_from_environment(app) unless command
|
164
|
-
command
|
165
|
-
end
|
166
|
-
|
167
|
-
private
|
168
|
-
|
169
|
-
def no_migrate?(hash)
|
170
|
-
hash.key?('migrate') && hash['migrate'] == false
|
171
|
-
end
|
172
|
-
|
173
|
-
def migration_command_from_config
|
174
|
-
config['migration_command'] if config['migrate'] || config['migration_command']
|
175
|
-
end
|
176
|
-
|
177
|
-
def migration_command_from_command_line(deploy_options)
|
178
|
-
if migrate = deploy_options['migrate']
|
179
|
-
migrate.respond_to?(:to_str) ? migrate.to_str : (config['migration_command'] || default_migration_command)
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
def migration_command_from_environment(app)
|
184
|
-
if deploy_config = deployment_configurations[app.name]
|
185
|
-
deploy_config['migrate']['command'] if deploy_config['migrate']['perform']
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def default_migration_command
|
190
|
-
'rake db:migrate'
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
end
|
@@ -1,166 +0,0 @@
|
|
1
|
-
require 'escape'
|
2
|
-
require 'net/ssh'
|
3
|
-
|
4
|
-
module EY
|
5
|
-
module Model
|
6
|
-
class Instance < ApiStruct.new(:id, :role, :name, :status, :amazon_id, :public_hostname, :environment)
|
7
|
-
alias :hostname :public_hostname
|
8
|
-
|
9
|
-
def adapter(app, verbose)
|
10
|
-
require 'engineyard-serverside-adapter'
|
11
|
-
EY::Serverside::Adapter.new("/usr/local/ey_resin/ruby/bin") do |args|
|
12
|
-
args.app = app.name
|
13
|
-
args.repo = app.repository_uri
|
14
|
-
args.instances = instances_data
|
15
|
-
args.verbose = verbose || ENV['DEBUG']
|
16
|
-
args.stack = environment.app_server_stack_name
|
17
|
-
args.framework_env = environment.framework_env
|
18
|
-
end
|
19
|
-
end
|
20
|
-
private :adapter
|
21
|
-
|
22
|
-
def deploy(app, ref, migration_command=nil, extra_configuration=nil, verbose=false)
|
23
|
-
successful, output = false, "Deploy initiated.\n"
|
24
|
-
deployment = Deployment.started(environment, app, ref, migration_command)
|
25
|
-
|
26
|
-
deploy_command = adapter(app, verbose).deploy do |args|
|
27
|
-
args.config = extra_configuration if extra_configuration
|
28
|
-
args.migrate = migration_command if migration_command
|
29
|
-
args.ref = deployment.resolved_ref
|
30
|
-
end
|
31
|
-
|
32
|
-
successful = invoke(deploy_command) { |chunk| output << chunk }
|
33
|
-
rescue Interrupt
|
34
|
-
output << "Interrupted. Deployment halted.\n"
|
35
|
-
EY.ui.warn "Interrupted."
|
36
|
-
EY.ui.warn "Recording canceled deployment and exiting..."
|
37
|
-
EY.ui.warn "WARNING: Interrupting again may result in a never-finished deployment in the deployment history on EY Cloud."
|
38
|
-
raise
|
39
|
-
rescue StandardError => e
|
40
|
-
EY.ui.info "Error encountered during deploy."
|
41
|
-
output << "Error encountered during deploy.\n#{e.class} #{e}\n"
|
42
|
-
raise
|
43
|
-
ensure
|
44
|
-
if deployment
|
45
|
-
deployment.finished(successful, output)
|
46
|
-
EY.ui.info "#{successful ? 'Successful' : 'Failed'} deployment recorded in EY Cloud"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def rollback(app, extra_configuration=nil, verbose=false)
|
51
|
-
rollback = adapter(app, verbose).rollback do |args|
|
52
|
-
args.config = extra_configuration if extra_configuration
|
53
|
-
end
|
54
|
-
invoke rollback
|
55
|
-
end
|
56
|
-
|
57
|
-
def put_up_maintenance_page(app, verbose=false)
|
58
|
-
invoke adapter(app, verbose).enable_maintenance_page
|
59
|
-
end
|
60
|
-
|
61
|
-
def take_down_maintenance_page(app, verbose=false)
|
62
|
-
invoke adapter(app, verbose).disable_maintenance_page
|
63
|
-
end
|
64
|
-
|
65
|
-
def has_app_code?
|
66
|
-
!["db_master", "db_slave"].include?(role.to_s)
|
67
|
-
end
|
68
|
-
|
69
|
-
def hostname_url
|
70
|
-
"http://#{hostname}" if hostname
|
71
|
-
end
|
72
|
-
|
73
|
-
protected
|
74
|
-
|
75
|
-
def engineyard_serverside_hostname
|
76
|
-
# If we tell engineyard-serverside to use 'localhost', it'll run
|
77
|
-
# commands on the instance directly (#system). If we give it the
|
78
|
-
# instance's actual hostname, it'll SSH to itself.
|
79
|
-
#
|
80
|
-
# Using 'localhost' instead of its EC2 hostname speeds up
|
81
|
-
# deploys on solos and single-app-server clusters significantly.
|
82
|
-
app_master? ? 'localhost' : hostname
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
|
-
def ssh(remote_command, verbose, &block)
|
88
|
-
raise(ArgumentError, "Block required!") unless block
|
89
|
-
|
90
|
-
exit_code = nil
|
91
|
-
cmd = Escape.shell_command(['bash', '-lc', remote_command])
|
92
|
-
block.call("Running command on #{environment.username}@#{hostname}.\n")
|
93
|
-
if cmd.respond_to?(:encoding) && cmd.respond_to?(:force_encoding)
|
94
|
-
block.call("Encoding: #{cmd.encoding.name}") if verbose
|
95
|
-
cmd.force_encoding('binary')
|
96
|
-
block.call(" => #{cmd.encoding.name}; __ENCODING__: #{__ENCODING__.name}; LANG: #{ENV['LANG']}; LC_CTYPE: #{ENV['LC_CTYPE']}\n") if verbose
|
97
|
-
end
|
98
|
-
EY.ui.debug(cmd)
|
99
|
-
block.call("Command: #{cmd}\n") if verbose
|
100
|
-
if ENV["NO_SSH"]
|
101
|
-
block.call("NO_SSH is set. No output.")
|
102
|
-
true
|
103
|
-
else
|
104
|
-
begin
|
105
|
-
options_for_ssh = {:paranoid => false}
|
106
|
-
options_for_ssh[:verbose] = ENV["DEBUG"].downcase.to_sym if ENV["DEBUG"]
|
107
|
-
Net::SSH.start(hostname, environment.username, options_for_ssh) do |net_ssh|
|
108
|
-
net_ssh.open_channel do |channel|
|
109
|
-
channel.exec cmd do |_, success|
|
110
|
-
unless success
|
111
|
-
block.call "Remote command execution failed"
|
112
|
-
return false
|
113
|
-
end
|
114
|
-
|
115
|
-
channel.on_data do |_, data|
|
116
|
-
block.call data
|
117
|
-
end
|
118
|
-
|
119
|
-
channel.on_extended_data do |_, _, data|
|
120
|
-
block.call data
|
121
|
-
end
|
122
|
-
|
123
|
-
channel.on_request("exit-status") do |_, data|
|
124
|
-
exit_code = data.read_long
|
125
|
-
end
|
126
|
-
|
127
|
-
channel.on_request("exit-signal") do |_, data|
|
128
|
-
exit_code = 255
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
net_ssh.loop
|
134
|
-
end
|
135
|
-
exit_code.zero?
|
136
|
-
rescue Net::SSH::AuthenticationFailed
|
137
|
-
raise EY::Error, "Authentication Failed: Please add your environment's ssh key with: ssh-add path/to/key"
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def invoke(action, &block)
|
143
|
-
action.call do |cmd|
|
144
|
-
ssh cmd, action.verbose do |chunk|
|
145
|
-
$stdout << chunk
|
146
|
-
block.call(chunk) if block
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def instances_data
|
152
|
-
environment.instances.select { |inst| inst.has_app_code? }.map do |i|
|
153
|
-
{
|
154
|
-
:hostname => i.engineyard_serverside_hostname,
|
155
|
-
:roles => [i.role],
|
156
|
-
:name => i.name,
|
157
|
-
}
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
def app_master?
|
162
|
-
environment.app_master == self
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|