engineyard 2.3.3 → 3.0.0
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 +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
|
+
|