engineyard 2.3.3 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/lib/engineyard/cli.rb +269 -167
- data/lib/engineyard/cli/api.rb +1 -1
- data/lib/engineyard/cli/recipes.rb +27 -23
- data/lib/engineyard/cli/ui.rb +1 -1
- data/lib/engineyard/cli/web.rb +33 -33
- data/lib/engineyard/serverside_runner.rb +8 -4
- data/lib/engineyard/templates/ey.yml.erb +4 -1
- data/lib/engineyard/thor.rb +12 -12
- data/lib/engineyard/version.rb +2 -2
- data/spec/ey/scp_spec.rb +176 -0
- data/spec/ey/servers_spec.rb +66 -0
- data/spec/support/helpers.rb +1 -1
- metadata +76 -65
data/lib/engineyard/cli/api.rb
CHANGED
@@ -10,7 +10,7 @@ module EY
|
|
10
10
|
attr_reader :token
|
11
11
|
|
12
12
|
def initialize(endpoint, ui, token = nil)
|
13
|
-
@client = EY::CloudClient.new(:
|
13
|
+
@client = EY::CloudClient.new(endpoint: endpoint, output: ui.out, user_agent: USER_AGENT)
|
14
14
|
@ui = ui
|
15
15
|
@eyrc = EY::EYRC.load
|
16
16
|
token_from('--api-token') { token } ||
|
@@ -13,12 +13,12 @@ module EY
|
|
13
13
|
you run '#{banner_base} recipes apply'.
|
14
14
|
DESC
|
15
15
|
|
16
|
-
method_option :environment, :
|
17
|
-
:
|
18
|
-
:
|
19
|
-
method_option :account, :
|
20
|
-
:
|
21
|
-
:
|
16
|
+
method_option :environment, type: :string, aliases: %w(-e),
|
17
|
+
required: true, default: '',
|
18
|
+
desc: "Environment in which to apply recipes"
|
19
|
+
method_option :account, type: :string, aliases: %w(-c),
|
20
|
+
required: true, default: '',
|
21
|
+
desc: "Name of the account in which the environment can be found"
|
22
22
|
def apply
|
23
23
|
environment = fetch_environment(options[:environment], options[:account])
|
24
24
|
apply_recipes(environment)
|
@@ -38,17 +38,17 @@ module EY
|
|
38
38
|
and also automatically each time you update/rebuild your instances.
|
39
39
|
DESC
|
40
40
|
|
41
|
-
method_option :environment, :
|
42
|
-
:
|
43
|
-
:
|
44
|
-
method_option :account, :
|
45
|
-
:
|
46
|
-
:
|
47
|
-
method_option :apply, :
|
48
|
-
:
|
49
|
-
method_option :file, :
|
50
|
-
:
|
51
|
-
:
|
41
|
+
method_option :environment, type: :string, aliases: %w(-e),
|
42
|
+
required: true, default: '',
|
43
|
+
desc: "Environment that will receive the recipes"
|
44
|
+
method_option :account, type: :string, aliases: %w(-c),
|
45
|
+
required: true, default: '',
|
46
|
+
desc: "Name of the account in which the environment can be found"
|
47
|
+
method_option :apply, type: :boolean,
|
48
|
+
desc: "Apply the recipes immediately after they are uploaded"
|
49
|
+
method_option :file, type: :string, aliases: %w(-f),
|
50
|
+
required: true, default: '',
|
51
|
+
desc: "Specify a gzipped tar file (.tgz) for upload instead of cookbooks/ directory"
|
52
52
|
def upload
|
53
53
|
environment = fetch_environment(options[:environment], options[:account])
|
54
54
|
upload_recipes(environment, options[:file])
|
@@ -80,7 +80,11 @@ module EY
|
|
80
80
|
end
|
81
81
|
|
82
82
|
recipes_file = Tempfile.new("recipes")
|
83
|
+
|
83
84
|
cmd = "tar czf '#{recipes_file.path}' cookbooks/"
|
85
|
+
if FileTest.exist?("data_bags")
|
86
|
+
cmd = cmd + " data_bags/"
|
87
|
+
end
|
84
88
|
|
85
89
|
unless system(cmd)
|
86
90
|
raise EY::Error, "Could not archive recipes.\nCommand `#{cmd}` exited with an error."
|
@@ -97,12 +101,12 @@ module EY
|
|
97
101
|
|
98
102
|
If the cookbooks directory already exists, an error will be raised.
|
99
103
|
DESC
|
100
|
-
method_option :environment, :
|
101
|
-
:
|
102
|
-
:
|
103
|
-
method_option :account, :
|
104
|
-
:
|
105
|
-
:
|
104
|
+
method_option :environment, type: :string, aliases: %w(-e),
|
105
|
+
required: true, default: '',
|
106
|
+
desc: "Environment for which to download the recipes"
|
107
|
+
method_option :account, type: :string, aliases: %w(-c),
|
108
|
+
required: true, default: '',
|
109
|
+
desc: "Name of the account in which the environment can be found"
|
106
110
|
def download
|
107
111
|
if File.exist?('cookbooks')
|
108
112
|
raise EY::Error, "Cannot download recipes, cookbooks directory already exists."
|
data/lib/engineyard/cli/ui.rb
CHANGED
data/lib/engineyard/cli/web.rb
CHANGED
@@ -3,17 +3,17 @@ module EY
|
|
3
3
|
class Web < EY::Thor
|
4
4
|
desc "enable [--environment/-e ENVIRONMENT]",
|
5
5
|
"Remove the maintenance page for this application in the given environment."
|
6
|
-
method_option :environment, :
|
7
|
-
:
|
8
|
-
:
|
9
|
-
method_option :app, :
|
10
|
-
:
|
11
|
-
:
|
12
|
-
method_option :account, :
|
13
|
-
:
|
14
|
-
:
|
15
|
-
method_option :verbose, :
|
16
|
-
:
|
6
|
+
method_option :environment, type: :string, aliases: %w(-e),
|
7
|
+
required: true, default: '',
|
8
|
+
desc: "Environment on which to take down the maintenance page"
|
9
|
+
method_option :app, type: :string, aliases: %w(-a),
|
10
|
+
required: true, default: '',
|
11
|
+
desc: "Name of the application whose maintenance page will be removed"
|
12
|
+
method_option :account, type: :string, aliases: %w(-c),
|
13
|
+
required: true, default: '',
|
14
|
+
desc: "Name of the account in which the environment can be found"
|
15
|
+
method_option :verbose, type: :boolean, aliases: %w(-v),
|
16
|
+
desc: "Be verbose"
|
17
17
|
def enable
|
18
18
|
app_env = fetch_app_environment(options[:app], options[:environment], options[:account])
|
19
19
|
ui.info "Taking down maintenance page for '#{app_env.app.name}' in '#{app_env.environment.name}'"
|
@@ -33,17 +33,17 @@ module EY
|
|
33
33
|
* public/maintenance.html
|
34
34
|
* public/system/maintenance.html.default
|
35
35
|
DESC
|
36
|
-
method_option :environment, :
|
37
|
-
:
|
38
|
-
:
|
39
|
-
method_option :app, :
|
40
|
-
:
|
41
|
-
:
|
42
|
-
method_option :account, :
|
43
|
-
:
|
44
|
-
:
|
45
|
-
method_option :verbose, :
|
46
|
-
:
|
36
|
+
method_option :environment, type: :string, aliases: %w(-e),
|
37
|
+
required: true, default: '',
|
38
|
+
desc: "Environment on which to put up the maintenance page"
|
39
|
+
method_option :app, type: :string, aliases: %w(-a),
|
40
|
+
required: true, default: '',
|
41
|
+
desc: "Name of the application whose maintenance page will be put up"
|
42
|
+
method_option :account, type: :string, aliases: %w(-c),
|
43
|
+
required: true, default: '',
|
44
|
+
desc: "Name of the account in which the environment can be found"
|
45
|
+
method_option :verbose, type: :boolean, aliases: %w(-v),
|
46
|
+
desc: "Be verbose"
|
47
47
|
def disable
|
48
48
|
app_env = fetch_app_environment(options[:app], options[:environment], options[:account])
|
49
49
|
ui.info "Putting up maintenance page for '#{app_env.app.name}' in '#{app_env.environment.name}'"
|
@@ -59,17 +59,17 @@ module EY
|
|
59
59
|
|
60
60
|
Note: Uses the version of the ey.yml currently checked out on the servers.
|
61
61
|
DESC
|
62
|
-
method_option :environment, :
|
63
|
-
:
|
64
|
-
:
|
65
|
-
method_option :app, :
|
66
|
-
:
|
67
|
-
:
|
68
|
-
method_option :account, :
|
69
|
-
:
|
70
|
-
:
|
71
|
-
method_option :verbose, :
|
72
|
-
:
|
62
|
+
method_option :environment, type: :string, aliases: %w(-e),
|
63
|
+
required: true, default: false,
|
64
|
+
desc: "Environment in which to deploy this application"
|
65
|
+
method_option :app, type: :string, aliases: %w(-a),
|
66
|
+
required: true, default: '',
|
67
|
+
desc: "Name of the application to deploy"
|
68
|
+
method_option :account, type: :string, aliases: %w(-c),
|
69
|
+
required: true, default: '',
|
70
|
+
desc: "Name of the account in which the environment can be found"
|
71
|
+
method_option :verbose, type: :boolean, aliases: %w(-v),
|
72
|
+
desc: "Be verbose"
|
73
73
|
def restart
|
74
74
|
app_env = fetch_app_environment(options[:app], options[:environment], options[:account])
|
75
75
|
ui.info "Restarting servers on #{app_env.hierarchy_name}"
|
@@ -71,9 +71,9 @@ module EY
|
|
71
71
|
def instances_data(instances, bridge)
|
72
72
|
instances.map do |i|
|
73
73
|
{
|
74
|
-
:
|
75
|
-
:
|
76
|
-
:
|
74
|
+
hostname: i.hostname == bridge ? 'localhost' : i.hostname,
|
75
|
+
roles: [i.role],
|
76
|
+
name: i.name,
|
77
77
|
}
|
78
78
|
end
|
79
79
|
end
|
@@ -115,7 +115,8 @@ Authentication Failed. Things to fix:
|
|
115
115
|
level = debug.downcase.to_sym
|
116
116
|
end
|
117
117
|
end
|
118
|
-
|
118
|
+
|
119
|
+
{paranoid: false, verbose: level, keepalive: true, keepalive_interval: 60}
|
119
120
|
end
|
120
121
|
|
121
122
|
def ssh(cmd, hostname, username, out, err)
|
@@ -143,6 +144,9 @@ Authentication Failed. Things to fix:
|
|
143
144
|
channel.on_request("exit-signal") do |_, data|
|
144
145
|
exit_code = 255
|
145
146
|
end
|
147
|
+
|
148
|
+
# sending eof declares no more data coming from this end (close stdin)
|
149
|
+
channel.eof!
|
146
150
|
end
|
147
151
|
end
|
148
152
|
|
@@ -38,7 +38,10 @@ defaults:
|
|
38
38
|
#
|
39
39
|
# By default, assets are detected using app/assets and config/application.rb.
|
40
40
|
#
|
41
|
-
# If you use rails assets
|
41
|
+
# If you use rails assets and you want Engine Yard to compile your assets
|
42
|
+
# during deploy, set this to true. If you want to compile assets locally
|
43
|
+
# before deploy, set this to false. Make sure you add `public/assets` to
|
44
|
+
# `.gitignore` if you want Engine Yard to precompile your assets.
|
42
45
|
#
|
43
46
|
# For more control over assets, set precompile_assets: false and
|
44
47
|
# run your precompile task in the deploy/before_compile_assets.rb deploy hook.
|
data/lib/engineyard/thor.rb
CHANGED
@@ -31,11 +31,11 @@ module EY
|
|
31
31
|
|
32
32
|
def serverside_runner(app_env, verbose, serverside_version = serverside_version, ignore_bad_bridge = false)
|
33
33
|
ServersideRunner.new({
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
:
|
38
|
-
:
|
34
|
+
bridge: app_env.environment.bridge!(ignore_bad_bridge).hostname,
|
35
|
+
app: app_env.app,
|
36
|
+
environment: app_env.environment,
|
37
|
+
verbose: verbose,
|
38
|
+
serverside_version: serverside_version
|
39
39
|
})
|
40
40
|
end
|
41
41
|
|
@@ -52,9 +52,9 @@ module EY
|
|
52
52
|
environment_name ||= use_default_environment
|
53
53
|
remotes = repo.remotes if in_repo?
|
54
54
|
constraints = {
|
55
|
-
:
|
56
|
-
:
|
57
|
-
:
|
55
|
+
environment_name: environment_name,
|
56
|
+
account_name: account_name,
|
57
|
+
remotes: remotes,
|
58
58
|
}
|
59
59
|
|
60
60
|
resolver = api.resolve_environments(constraints)
|
@@ -84,10 +84,10 @@ module EY
|
|
84
84
|
environment_name ||= use_default_environment
|
85
85
|
remotes = repo.remotes if in_repo?
|
86
86
|
constraints = {
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
90
|
-
:
|
87
|
+
app_name: app_name,
|
88
|
+
environment_name: environment_name,
|
89
|
+
account_name: account_name,
|
90
|
+
remotes: remotes,
|
91
91
|
}
|
92
92
|
|
93
93
|
if constraints.all? { |k,v| v.nil? || v.empty? || v.to_s.empty? }
|
data/lib/engineyard/version.rb
CHANGED
data/spec/ey/scp_spec.rb
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples_for "running ey scp" do
|
4
|
+
given "integration"
|
5
|
+
|
6
|
+
def extra_ey_options
|
7
|
+
{:prepend_to_path => {'scp' => "#!/bin/sh\necho scp $*"}}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
shared_examples_for "running ey scp for select role" do
|
12
|
+
given "integration"
|
13
|
+
|
14
|
+
def extra_ey_options
|
15
|
+
{:prepend_to_path => {'scp' => "#!/bin/sh\necho scp $*"}}
|
16
|
+
end
|
17
|
+
|
18
|
+
def command_to_run(opts)
|
19
|
+
cmd = ["scp", opts[:from], opts[:to]].compact + (@scp_flag || [])
|
20
|
+
cmd << "--environment" << opts[:environment] if opts[:environment]
|
21
|
+
cmd << "--quiet" if opts[:quiet]
|
22
|
+
cmd
|
23
|
+
end
|
24
|
+
|
25
|
+
it "runs the command on the right servers" do
|
26
|
+
login_scenario "one app, one environment"
|
27
|
+
ey command_to_run(from: "from", to: "to", environment: 'giblets', verbose: true)
|
28
|
+
@hosts.each do |host_prefix|
|
29
|
+
@raw_ssh_commands.grep(/^scp from turkey@#{host_prefix}.+:to$/).should_not be_empty
|
30
|
+
end
|
31
|
+
@raw_ssh_commands.grep(/^scp from turkey@.+:to$/).count.should == @hosts.count
|
32
|
+
end
|
33
|
+
|
34
|
+
it "is quiet" do
|
35
|
+
login_scenario "one app, one environment"
|
36
|
+
ey command_to_run(from: "from", to: "to", environment: 'giblets', quiet: true)
|
37
|
+
@out.should =~ /scp.*from.*to/
|
38
|
+
@out.should_not =~ /Loading application data/
|
39
|
+
end
|
40
|
+
|
41
|
+
it "raises an error when there are no matching hosts" do
|
42
|
+
login_scenario "one app, one environment, no instances"
|
43
|
+
ey command_to_run({from: "from", to: "to", environment: 'giblets', verbose: true}), expect_failure: true
|
44
|
+
end
|
45
|
+
|
46
|
+
it "errors correctly when no file paths are specified" do
|
47
|
+
login_scenario "one app, one environment"
|
48
|
+
ey command_to_run({environment: 'giblets', verbose: true}), expect_failure: true
|
49
|
+
ey command_to_run({from: "from", environment: 'giblets', verbose: true}), expect_failure: true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "ey scp" do
|
54
|
+
include_examples "running ey scp"
|
55
|
+
|
56
|
+
before(:all) do
|
57
|
+
login_scenario "one app, many environments"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "complains if it has no app master" do
|
61
|
+
ey %w[scp from to -e bakon], :expect_failure => true
|
62
|
+
@err.should =~ /'bakon' does not have any matching instances/
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "ey scp with an ambiguous git repo" do
|
68
|
+
include_examples "running ey scp"
|
69
|
+
def command_to_run(_) %w[scp from to] end
|
70
|
+
include_examples "it requires an unambiguous git repo"
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "ey scp" do
|
74
|
+
include_examples "running ey scp"
|
75
|
+
|
76
|
+
def command_to_run(opts)
|
77
|
+
cmd = %w[scp HOST:from to]
|
78
|
+
cmd << "--environment" << opts[:environment] if opts[:environment]
|
79
|
+
cmd << "--account" << opts[:account] if opts[:account]
|
80
|
+
cmd
|
81
|
+
end
|
82
|
+
|
83
|
+
def verify_ran(scenario)
|
84
|
+
scp_target = scenario[:ssh_username] + '@' + scenario[:master_hostname]
|
85
|
+
@raw_ssh_commands.should == ["scp #{scp_target}:from to"]
|
86
|
+
end
|
87
|
+
|
88
|
+
include_examples "it takes an environment name and an account name"
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "ey scp --all" do
|
92
|
+
before do
|
93
|
+
@scp_flag = %w[--all]
|
94
|
+
@hosts = %w(app_hostname
|
95
|
+
app_master_hostname
|
96
|
+
util_fluffy_hostname
|
97
|
+
util_rocky_hostname
|
98
|
+
db_master_hostname
|
99
|
+
db_slave_1_hostname
|
100
|
+
db_slave_2_hostname)
|
101
|
+
end
|
102
|
+
|
103
|
+
include_examples "running ey scp"
|
104
|
+
include_examples "running ey scp for select role"
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "ey scp --app-servers" do
|
108
|
+
before do
|
109
|
+
@scp_flag = %w[--app-servers]
|
110
|
+
@hosts = %w(app_hostname app_master_hostname)
|
111
|
+
end
|
112
|
+
|
113
|
+
include_examples "running ey scp"
|
114
|
+
include_examples "running ey scp for select role"
|
115
|
+
end
|
116
|
+
|
117
|
+
describe "ey scp --db-master" do
|
118
|
+
before do
|
119
|
+
@scp_flag = %w[--db-master]
|
120
|
+
@hosts = %w(db_master_hostname)
|
121
|
+
end
|
122
|
+
|
123
|
+
include_examples "running ey scp"
|
124
|
+
include_examples "running ey scp for select role"
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "ey scp --db-slaves" do
|
128
|
+
before do
|
129
|
+
@scp_flag = %w[--db-slaves]
|
130
|
+
@hosts = %w(db_slave_1_hostname db_slave_2_hostname)
|
131
|
+
end
|
132
|
+
|
133
|
+
include_examples "running ey scp"
|
134
|
+
include_examples "running ey scp for select role"
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "ey scp --db-servers" do
|
138
|
+
before do
|
139
|
+
@scp_flag = %w[--db-servers]
|
140
|
+
@hosts = %w(db_master_hostname db_slave_1_hostname db_slave_2_hostname)
|
141
|
+
end
|
142
|
+
|
143
|
+
include_examples "running ey scp"
|
144
|
+
include_examples "running ey scp for select role"
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "ey scp --utilities" do
|
148
|
+
before do
|
149
|
+
@scp_flag = %w[--utilities]
|
150
|
+
@hosts = %w(util_fluffy_hostname util_rocky_hostname)
|
151
|
+
end
|
152
|
+
|
153
|
+
include_examples "running ey scp"
|
154
|
+
include_examples "running ey scp for select role"
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "ey scp --utilities fluffy" do
|
158
|
+
before do
|
159
|
+
@scp_flag = %w[--utilities fluffy]
|
160
|
+
@hosts = %w(util_fluffy_hostname)
|
161
|
+
end
|
162
|
+
|
163
|
+
include_examples "running ey scp"
|
164
|
+
include_examples "running ey scp for select role"
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "ey scp --utilities fluffy rocky" do
|
168
|
+
before do
|
169
|
+
@scp_flag = %w[--utilities fluffy rocky]
|
170
|
+
@hosts = %w(util_fluffy_hostname util_rocky_hostname)
|
171
|
+
end
|
172
|
+
|
173
|
+
include_examples "running ey scp"
|
174
|
+
include_examples "running ey scp for select role"
|
175
|
+
end
|
176
|
+
|