engineyard 1.4.29 → 1.7.0.pre2
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.
- 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
|