engineyard 2.2.1 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +75 -18
- data/lib/engineyard.rb +6 -6
- data/lib/engineyard/cli.rb +131 -11
- data/lib/engineyard/cli/ui.rb +42 -0
- data/lib/engineyard/config.rb +39 -105
- data/lib/engineyard/deploy_config.rb +19 -16
- data/lib/engineyard/error.rb +1 -1
- data/lib/engineyard/serverside_runner.rb +1 -1
- data/lib/engineyard/templates.rb +6 -0
- data/lib/engineyard/templates/ey.yml.erb +193 -0
- data/lib/engineyard/templates/ey_yml.rb +119 -0
- data/lib/engineyard/version.rb +2 -2
- data/spec/engineyard/deploy_config_spec.rb +33 -67
- data/spec/ey/deploy_spec.rb +54 -94
- data/spec/ey/init_spec.rb +123 -0
- data/spec/ey/rebuild_spec.rb +1 -1
- data/spec/ey/servers_spec.rb +143 -0
- data/spec/ey/timeout_deploy_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -7
- data/spec/support/helpers.rb +43 -1
- data/spec/support/shared_behavior.rb +4 -1
- metadata +19 -11
- data/lib/engineyard/deploy_config/migrate.rb +0 -129
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MWMzMTAwYWJkYWMyYjcxNjFhZjc0OThjZDM5M2E1MTJkMzIwNTg4Yg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NGM3OWVjYTI2ZWJmOGM5MzI3MjdiMjc3NDMzMTRiMmM3YTA4ZDFiNg==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ZGI4ZWRlNWE3NWIzZWE0MTc4ODBlMDcxNjllZTk3M2Y3NTE3ZmE3MDNjMzVk
|
10
|
+
ODgyOTc1ZjUzMjI2OGRhYTNmZmM4OGU3YzQzMGQxZmFiNGQ4ZTg5MWI4NzJi
|
11
|
+
NGY1M2Q1MWM4ODRhZWUyY2RkZjI2MzhjOTlhYTQzNzBjODgwMmM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OTY4OWZhOGZjZDdhYjY4NDc5OWE4ZjA5OTJhMjg4ZDFhNjVjMDFmMzM1ZjRj
|
14
|
+
ODJhMjNiYWY3MzBhZGMyNWI2MzFmNDkyNTliZmY1MzVhNWM5OGE2NjIzY2U1
|
15
|
+
YzU5OTU5Y2RjMjk4MDBlYTI5ZGM3ZDRmZDQxZmRjZGFiN2I4YmI=
|
data/README.md
CHANGED
@@ -18,38 +18,56 @@ you for your Engine Yard email and password.
|
|
18
18
|
### Configuration
|
19
19
|
|
20
20
|
The `ey.yml` file allows options to be saved for each environment to which an
|
21
|
-
application is deployed.
|
21
|
+
application is deployed.
|
22
|
+
|
23
|
+
A typical Rails application will have a `config/ey.yml` like this:
|
24
|
+
|
25
|
+
---
|
26
|
+
# This is all you need for a typical rails application.
|
27
|
+
defaults:
|
28
|
+
migrate: true
|
29
|
+
migration_command: rake db:migrate
|
30
|
+
precompile_assets: true
|
31
|
+
|
32
|
+
The following `ey.yml` file shows other things that can be customized.
|
33
|
+
A typical application will not need most of these options.
|
22
34
|
|
23
|
-
$ cat config/ey.yml
|
24
35
|
---
|
25
36
|
# 'defaults' applies to all environments running this application.
|
37
|
+
# Only set these options if needed. The defaults are correct for most applications.
|
26
38
|
defaults:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
39
|
+
bundler: detect # By default, bundler is detected via Gemfile. Options: true: always run bundler; false: never run bundler
|
40
|
+
composer: detect # By default, composer is detected via composer.lock. Options: true: always run composer; false: never run composer
|
41
|
+
npm: detect # By default, npm is detected via package.json. Options: true: always run npm; false: never run npm
|
42
|
+
bundle_without: GROUP1 GROUP2 # exclude groups on bundle install (default: test development)
|
43
|
+
bundle_options: --OPTION # extra bundle install options (--local, --quiet, etc; does not override bundle_without)
|
44
|
+
copy_exclude: # don't rsync the following dirs (some people like to skip .git)
|
45
|
+
- SOME_LARGE_DIR
|
31
46
|
maintenance_on_restart: false # show maintenance page during app restart (default: false except for glassfish and mongrel)
|
32
|
-
maintenance_on_migrate:
|
47
|
+
maintenance_on_migrate: true # show maintenance page during migrations (default: true)
|
33
48
|
precompile_assets: true # enables rails assets precompilation (default: inferred using app/assets and config/application.rb)
|
34
49
|
precomplie_assets_task: assets:precompile # override the assets:precompile rake task
|
35
|
-
precompile_unchanged_assets:
|
36
|
-
asset_dependencies:
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
-
|
41
|
-
-
|
42
|
-
-
|
50
|
+
precompile_unchanged_assets: false # if true, does not check git for changes before precompiling assets.
|
51
|
+
asset_dependencies: # a list of relative paths to search for asset changes during each deploy.
|
52
|
+
- app/assets # default
|
53
|
+
- lib/assets # default
|
54
|
+
- vendor/assets # default
|
55
|
+
- Gemfile.lock # default
|
56
|
+
- config/routes.rb # default
|
57
|
+
- config/application.rb # default
|
58
|
+
- config/requirejs.yml # custom option (be sure to include defaults if you specify this option)
|
59
|
+
asset_strategy: shifting # choose an alternet asset management strategy. See rails_assets/strategy.rb for more info.
|
60
|
+
asset_roles: :all # specify on which roles to compile assets (default: [:app, :app_master, :solo])
|
43
61
|
ignore_database_adapter_warning: true # hide database adapter warning if you don't use MySQL or PostgreSQL (default: false)
|
44
62
|
|
45
63
|
# Environment specific options apply only to a single environment and override settings in defaults.
|
46
64
|
environments:
|
47
65
|
env_production:
|
48
66
|
precompile_unchanged_assets: true # precompiles assets even if no changes would be detected (does not check for changes at all).
|
49
|
-
|
67
|
+
asset_strategy: shifting # choose an alternet asset management strategy (shifting, cleaning, private, shared)
|
50
68
|
asset_roles: :all # specify on which roles to compile assets (default: [:app, :app_master, :solo] - must be an Array)
|
51
69
|
env_staging
|
52
|
-
|
70
|
+
asset_strategy: private # Use an asset management that always refreshes, so staging enviroments don't get conflicts
|
53
71
|
|
54
72
|
These options in `ey.yml` will only work if the file is committed to your
|
55
73
|
application repository. Make sure to commit this file. Different branches
|
@@ -59,6 +77,19 @@ found in the deploying commit will be used for the current deploy.
|
|
59
77
|
|
60
78
|
### Commands
|
61
79
|
|
80
|
+
#### ey init
|
81
|
+
|
82
|
+
Initialize a repository for deployment on Engine Yard Cloud.
|
83
|
+
|
84
|
+
This command writes or updates an ey.yml file which explains options available
|
85
|
+
for customizing the deployment process.
|
86
|
+
|
87
|
+
`ey init` can be run in existing applications to update the ey.yml file
|
88
|
+
without losing existing settings.
|
89
|
+
|
90
|
+
NOTE: Please verify all settings and changes after running ey init for
|
91
|
+
the first time.
|
92
|
+
|
62
93
|
#### ey deploy
|
63
94
|
|
64
95
|
This command must be run within the current directory containing the app to be
|
@@ -78,7 +109,7 @@ Options:
|
|
78
109
|
-c, [--account=ACCOUNT] # Name of the account in which the environment can be found
|
79
110
|
-a, [--app=APP] # Name of the application to deploy
|
80
111
|
-e, [--environment=ENVIRONMENT] # Environment in which to deploy this application
|
81
|
-
-m, [--migrate=MIGRATE] # Run migrations via [MIGRATE]
|
112
|
+
-m, [--migrate=MIGRATE] # Run migrations via [MIGRATE]; use --no-migrate to avoid running migrations
|
82
113
|
-v, [--verbose] # Be verbose
|
83
114
|
[--ignore-default-branch] # Force a deploy of the specified branch even if a default is set
|
84
115
|
[--ignore-bad-master] # Force a deploy even if the master is in a bad state
|
@@ -129,6 +160,32 @@ Options:
|
|
129
160
|
-s, [--simple] # Print each environment name on its own on a new line
|
130
161
|
-a, [--all] # Show all environments, not just ones associated with this application.
|
131
162
|
|
163
|
+
#### ey servers
|
164
|
+
|
165
|
+
List all servers on an environment.
|
166
|
+
|
167
|
+
Options:
|
168
|
+
|
169
|
+
-c, [--account=ACCOUNT] # Name of the account in which the environment can be found
|
170
|
+
-e, [--environment=ENVIRONMENT] # Show only servers in the named environment
|
171
|
+
-u, [--user] # Print the user@ in front of the server hostname to make ssh connections simpler
|
172
|
+
-s, [--simple] # Print each server on a new line with hostname, role, and name separated by tabs
|
173
|
+
-S, [--host] # Print each server on a new line with hostname only. Use -Su for 'user@host'
|
174
|
+
|
175
|
+
Example output:
|
176
|
+
|
177
|
+
$ ey servers -s
|
178
|
+
ec2-10-0-0-0.us-west-2.compute.amazonaws.com i-aabbccdd app_master
|
179
|
+
ec2-10-0-0-1.us-west-2.compute.amazonaws.com i-bbccddee app
|
180
|
+
ec2-10-0-0-2.us-west-2.compute.amazonaws.com i-ccddeeff db_master
|
181
|
+
ec2-10-0-0-3.us-west-2.compute.amazonaws.com i-ddeeffaa util resque
|
182
|
+
|
183
|
+
$ ey servers -Su
|
184
|
+
deploy@ec2-10-0-0-0.us-west-2.compute.amazonaws.com
|
185
|
+
deploy@ec2-10-0-0-1.us-west-2.compute.amazonaws.com
|
186
|
+
deploy@ec2-10-0-0-2.us-west-2.compute.amazonaws.com
|
187
|
+
deploy@ec2-10-0-0-3.us-west-2.compute.amazonaws.com
|
188
|
+
|
132
189
|
|
133
190
|
#### ey logs
|
134
191
|
|
data/lib/engineyard.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'engineyard-cloud-client'
|
2
|
-
|
3
1
|
module EY
|
4
|
-
require 'engineyard/version'
|
5
|
-
require 'engineyard/error'
|
6
|
-
require 'engineyard/config'
|
7
|
-
|
8
2
|
autoload :Repo, 'engineyard/repo'
|
3
|
+
autoload :Templates, 'engineyard/templates'
|
9
4
|
end
|
5
|
+
|
6
|
+
require 'engineyard-cloud-client'
|
7
|
+
require 'engineyard/version'
|
8
|
+
require 'engineyard/error'
|
9
|
+
require 'engineyard/config'
|
data/lib/engineyard/cli.rb
CHANGED
@@ -4,6 +4,7 @@ require 'engineyard/thor'
|
|
4
4
|
require 'engineyard/deploy_config'
|
5
5
|
require 'engineyard/serverside_runner'
|
6
6
|
require 'launchy'
|
7
|
+
require 'fileutils'
|
7
8
|
|
8
9
|
module EY
|
9
10
|
class CLI < EY::Thor
|
@@ -36,10 +37,52 @@ module EY
|
|
36
37
|
raise
|
37
38
|
end
|
38
39
|
|
39
|
-
class_option :api_token, :type => :string, :desc => "Use
|
40
|
+
class_option :api_token, :type => :string, :desc => "Use API_TOKEN to authenticate this command"
|
40
41
|
class_option :serverside_version, :type => :string, :desc => "Please use with care! Override deploy system version (same as ENV variable ENGINEYARD_SERVERSIDE_VERSION)"
|
41
42
|
class_option :quiet, :aliases => %w[-q], :type => :boolean, :desc => "Quieter CLI output."
|
42
43
|
|
44
|
+
desc "init",
|
45
|
+
"Initialize the current directory with an ey.yml configuration file."
|
46
|
+
long_desc <<-DESC
|
47
|
+
Initialize the current directory with an ey.yml configuration file.
|
48
|
+
|
49
|
+
Please read the generated file and make adjustments.
|
50
|
+
Many applications will need only the default behavior.
|
51
|
+
For reference, many available options are explained in the generated file.
|
52
|
+
|
53
|
+
IMPORTANT: THE GENERATED FILE '#{EY::Config.pathname_for_write}'
|
54
|
+
MUST BE COMMITTED TO YOUR REPOSITORY OR OPTIONS WILL NOT BE LOADED.
|
55
|
+
DESC
|
56
|
+
method_option :path, :type => :string, :aliases => %w(-p),
|
57
|
+
:desc => "Path for ey.yml (supported paths: #{EY::Config::CONFIG_FILES.join(', ')})"
|
58
|
+
def init
|
59
|
+
unless EY::Repo.exist?
|
60
|
+
raise EY::Error, "Working directory is not a repository. Aborting."
|
61
|
+
end
|
62
|
+
|
63
|
+
path = Pathname.new(options['path'] || EY::Config.pathname_for_write)
|
64
|
+
|
65
|
+
existing = {}
|
66
|
+
if path.exist?
|
67
|
+
ui.warn "Reinitializing existing file: #{path}"
|
68
|
+
existing = EY::Config.load_config
|
69
|
+
end
|
70
|
+
|
71
|
+
template = EY::Templates::EyYml.new(existing)
|
72
|
+
template.write(path)
|
73
|
+
|
74
|
+
ui.info <<-GIT
|
75
|
+
|
76
|
+
Configuration generated: #{path}
|
77
|
+
Go look at it, then add it to your repository!
|
78
|
+
|
79
|
+
\tgit add #{path}
|
80
|
+
\tgit commit -m "Add generated #{path} from ey init"
|
81
|
+
|
82
|
+
GIT
|
83
|
+
end
|
84
|
+
|
85
|
+
|
43
86
|
desc "deploy [--environment ENVIRONMENT] [--ref GIT-REF]",
|
44
87
|
"Deploy specified branch, tag, or sha to specified environment."
|
45
88
|
long_desc <<-DESC
|
@@ -57,7 +100,7 @@ module EY
|
|
57
100
|
:desc => "Force a deploy even if the master is in a bad state"
|
58
101
|
method_option :migrate, :type => :string, :aliases => %w(-m),
|
59
102
|
:lazy_default => true,
|
60
|
-
:desc => "Run migrations via [MIGRATE]
|
103
|
+
:desc => "Run migrations via [MIGRATE]; use --no-migrate to avoid running migrations"
|
61
104
|
method_option :ref, :type => :string, :aliases => %w(-r --branch --tag),
|
62
105
|
:required => true, :default => '',
|
63
106
|
:desc => "Git ref to deploy. May be a branch, a tag, or a SHA. Use -R to deploy a different ref if a default is set."
|
@@ -272,6 +315,47 @@ WARNING: Interrupting again may prevent Engine Yard Cloud from recording this
|
|
272
315
|
end
|
273
316
|
map "envs" => :environments
|
274
317
|
|
318
|
+
desc "servers", "List servers for an environment."
|
319
|
+
long_desc <<-DESC
|
320
|
+
Display a list of all servers on an environment.
|
321
|
+
Specify -s (--simple) to make parsing the output easier
|
322
|
+
or -uS (--user --host) to output bash loop friendly "user@hostname"
|
323
|
+
DESC
|
324
|
+
|
325
|
+
method_option :simple, :type => :boolean, :aliases => %(-s),
|
326
|
+
:desc => "Display all information in a simplified format without extra text or column alignment"
|
327
|
+
method_option :host, :type => :boolean, :aliases => %(-S),
|
328
|
+
:desc => "Display only hostnames, one per newline (use options -uS (--user --host) for user@hostname)"
|
329
|
+
method_option :user, :type => :boolean, :aliases => %w(-u),
|
330
|
+
:desc => "Include the ssh username in front of the hostname for easy SSH scripting"
|
331
|
+
method_option :account, :type => :string, :aliases => %w(-c),
|
332
|
+
:required => true, :default => '',
|
333
|
+
:desc => "Find environment in this account"
|
334
|
+
method_option :environment, :type => :string, :aliases => %w(-e),
|
335
|
+
:required => true, :default => '',
|
336
|
+
:desc => "Show servers in environment matching environment name"
|
337
|
+
def servers
|
338
|
+
if options[:environment] == '' && options[:account] == ''
|
339
|
+
repo.fail_on_no_remotes!
|
340
|
+
end
|
341
|
+
|
342
|
+
environment = nil
|
343
|
+
ui.mute_if(options[:simple] || options[:host]) do
|
344
|
+
environment = fetch_environment(options[:environment], options[:account])
|
345
|
+
end
|
346
|
+
|
347
|
+
username = options[:user] && environment.username
|
348
|
+
servers = environment.instances
|
349
|
+
|
350
|
+
if options[:host]
|
351
|
+
ui.print_hostnames(servers, username)
|
352
|
+
elsif options[:simple]
|
353
|
+
ui.print_simple_servers(servers, username)
|
354
|
+
else
|
355
|
+
ui.print_servers(servers, environment.hierarchy_name, username)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
275
359
|
desc "rebuild [--environment ENVIRONMENT]", "Rebuild specified environment."
|
276
360
|
long_desc <<-DESC
|
277
361
|
Engine Yard's main configuration run occurs on all servers. Mainly used to fix
|
@@ -338,7 +422,9 @@ WARNING: Interrupting again may prevent Engine Yard Cloud from recording this
|
|
338
422
|
long_desc <<-DESC
|
339
423
|
If a command is supplied, it will be run, otherwise a session will be
|
340
424
|
opened. The application master is used for environments with clusters.
|
341
|
-
|
425
|
+
|
426
|
+
Option --all requires a command to be supplied and runs it on all servers or
|
427
|
+
pass --each to connect to each server one after another.
|
342
428
|
|
343
429
|
Note: this command is a bit picky about its ordering. To run a command with arguments on
|
344
430
|
all servers, like "rm -f /some/file", you need to order it like so:
|
@@ -365,22 +451,56 @@ WARNING: Interrupting again may prevent Engine Yard Cloud from recording this
|
|
365
451
|
:desc => "Run command on the utility servers with the given names. If no names are given, run on all utility servers."
|
366
452
|
method_option :shell, :type => :string, :default => 'bash', :aliases => %w(-s),
|
367
453
|
:desc => "Run command in a shell other than bash. Use --no-shell to run the command without a shell."
|
454
|
+
method_option :pty, :type => :boolean, :default => false, :aliases => %w(-t),
|
455
|
+
:desc => "If a command is given, run in a pty. Required for interactive commands like sudo."
|
456
|
+
method_option :bind_address, :type => :string, :aliases => %w(-L),
|
457
|
+
:desc => "When a command is not given, pass -L to the ssh command."
|
458
|
+
method_option :each, :type => :boolean, :default => false,
|
459
|
+
:desc => "If no command is given, connect to multiple servers each one after another, instead of exiting with an error."
|
368
460
|
|
369
461
|
def ssh(cmd=nil)
|
370
462
|
environment = fetch_environment(options[:environment], options[:account])
|
371
|
-
|
463
|
+
instances = ssh_hosts(options, environment)
|
464
|
+
ssh_opts = []
|
465
|
+
|
466
|
+
if cmd
|
467
|
+
if options[:shell]
|
468
|
+
cmd = Escape.shell_command([options[:shell],'-lc',cmd])
|
469
|
+
end
|
372
470
|
|
373
|
-
|
471
|
+
if options[:pty]
|
472
|
+
ssh_opts = ["-t"]
|
473
|
+
elsif cmd =~ /sudo/
|
474
|
+
ui.warn "sudo commands often need a tty to run correctly. Use -t option to spawn a tty."
|
475
|
+
end
|
476
|
+
else
|
477
|
+
if instances.size != 1 && options[:each] == false
|
478
|
+
raise NoCommandError.new
|
479
|
+
end
|
374
480
|
|
375
|
-
|
376
|
-
|
481
|
+
if options[:bind_address]
|
482
|
+
ssh_opts = ["-L", options[:bind_address]]
|
483
|
+
end
|
377
484
|
end
|
378
485
|
|
379
|
-
|
380
|
-
|
486
|
+
ssh_cmd = ["ssh"]
|
487
|
+
ssh_cmd += ssh_opts
|
488
|
+
|
489
|
+
trap(:INT) { abort "Aborting..." }
|
490
|
+
|
491
|
+
exits = instances.map do |instance|
|
492
|
+
host = instance.public_hostname
|
493
|
+
name = instance.name ? "#{instance.role} (#{instance.name})" : instance.role
|
494
|
+
ui.info "\nConnecting to #{name} #{host}..."
|
495
|
+
unless cmd
|
496
|
+
ui.info "Ctrl + C to abort"
|
497
|
+
sleep 1.3
|
498
|
+
end
|
499
|
+
system Escape.shell_command((ssh_cmd + ["#{environment.username}@#{host}"] + [cmd]).compact)
|
381
500
|
$?.exitstatus
|
382
501
|
end
|
383
|
-
|
502
|
+
|
503
|
+
exit exits.detect {|status| status != 0 } || 0
|
384
504
|
end
|
385
505
|
|
386
506
|
no_tasks do
|
@@ -407,7 +527,7 @@ WARNING: Interrupting again may prevent Engine Yard Cloud from recording this
|
|
407
527
|
|
408
528
|
instances = environment.instances.select {|instance| filter[instance] }
|
409
529
|
raise NoInstancesError.new(environment.name) if instances.empty?
|
410
|
-
return instances
|
530
|
+
return instances
|
411
531
|
end
|
412
532
|
end
|
413
533
|
|
data/lib/engineyard/cli/ui.rb
CHANGED
@@ -128,6 +128,48 @@ module EY
|
|
128
128
|
return ''
|
129
129
|
end
|
130
130
|
|
131
|
+
def mute_if(bool, &block)
|
132
|
+
bool ? mute(&block) : yield
|
133
|
+
end
|
134
|
+
|
135
|
+
def server_tuples(servers, username=nil)
|
136
|
+
user = username && "#{username}@"
|
137
|
+
|
138
|
+
servers.map do |server|
|
139
|
+
host = "#{user}#{server.hostname}"
|
140
|
+
[host, server.amazon_id, server.role, server.name]
|
141
|
+
end
|
142
|
+
end
|
143
|
+
private :server_tuples
|
144
|
+
|
145
|
+
def print_hostnames(servers, username=nil)
|
146
|
+
server_tuples(servers, username).each do |server_tuple|
|
147
|
+
puts server_tuple.first
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def print_simple_servers(servers, username=nil)
|
152
|
+
server_tuples(servers, username).each do |server_tuple|
|
153
|
+
puts server_tuple.join("\t")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def print_servers(servers, name, username=nil)
|
158
|
+
tuples = server_tuples(servers, username)
|
159
|
+
count = tuples.size
|
160
|
+
puts "# #{count} server#{count == 1 ? '' : 's'} on #{name}"
|
161
|
+
|
162
|
+
host_width = tuples.map {|s| s[0].length }.max
|
163
|
+
host_format = "%-#{host_width}s" # "%-10s" left align
|
164
|
+
|
165
|
+
role_width = tuples.map {|s| s[2].length }.max
|
166
|
+
role_format = "%-#{role_width}s" # "%-10s" left align
|
167
|
+
|
168
|
+
tuples.each do |server_tuple|
|
169
|
+
puts "#{host_format}\t%s\t#{role_format}\t%s" % server_tuple
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
131
173
|
def print_simple_envs(envs)
|
132
174
|
puts envs.map{|env| env.name }.uniq.sort
|
133
175
|
end
|
data/lib/engineyard/config.rb
CHANGED
@@ -5,19 +5,37 @@ require 'engineyard/error'
|
|
5
5
|
|
6
6
|
module EY
|
7
7
|
class Config
|
8
|
+
# This order is important.
|
8
9
|
CONFIG_FILES = ["config/ey.yml", "ey.yml"].map {|path| Pathname.new(path)}.freeze
|
10
|
+
TEMPLATE_PATHNAME = Pathname.new(__FILE__).dirname.join('templates','ey.yml').freeze
|
9
11
|
|
10
|
-
|
12
|
+
def self.pathname_for_write
|
13
|
+
pathname || CONFIG_FILES.find{|pathname| pathname.dirname.exist? }
|
14
|
+
end
|
11
15
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
def self.pathname
|
17
|
+
CONFIG_FILES.find{|pathname| pathname.exist? }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.template_pathname
|
21
|
+
TEMPLATE_PATHNAME
|
22
|
+
end
|
16
23
|
|
17
|
-
|
18
|
-
|
24
|
+
def self.load_config(path = pathname)
|
25
|
+
config = YAML.load_file(path.to_s) if path && path.exist?
|
26
|
+
config ||= {} # load_file returns `false' when the file is empty
|
27
|
+
|
28
|
+
unless Hash === config
|
29
|
+
raise "ey.yml load error: Expected a Hash but a #{config.class.name} was returned."
|
19
30
|
end
|
31
|
+
config
|
32
|
+
end
|
20
33
|
|
34
|
+
attr_reader :path
|
35
|
+
|
36
|
+
def initialize(file = nil)
|
37
|
+
@path = file ? Pathname.new(file) : self.class.pathname
|
38
|
+
@config = self.class.load_config(@path)
|
21
39
|
@config["environments"] ||= {}
|
22
40
|
end
|
23
41
|
|
@@ -79,76 +97,6 @@ module EY
|
|
79
97
|
EnvironmentConfig.new(environments[environment_name], environment_name, self)
|
80
98
|
end
|
81
99
|
|
82
|
-
def set_environment_option(environment_name, key, value)
|
83
|
-
environments[environment_name] ||= {}
|
84
|
-
environments[environment_name][key] = value
|
85
|
-
write_ey_yaml
|
86
|
-
end
|
87
|
-
|
88
|
-
def write_ey_yaml
|
89
|
-
ensure_path
|
90
|
-
comments = ey_yml_comments
|
91
|
-
@path.open('w') do |f|
|
92
|
-
f.puts comments
|
93
|
-
f.puts YAML.dump(@config)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def set_default_option(key, value)
|
98
|
-
defaults[key] = value
|
99
|
-
write_ey_yaml
|
100
|
-
end
|
101
|
-
|
102
|
-
EY_YML_HINTS = <<-HINTS
|
103
|
-
# ey.yml supports many deploy configuration options when committed in an
|
104
|
-
# application's repository.
|
105
|
-
#
|
106
|
-
# Valid locations: REPO_ROOT/ey.yml or REPO_ROOT/config/ey.yml.
|
107
|
-
#
|
108
|
-
# Examples options (defaults apply to all environments for this application):
|
109
|
-
#
|
110
|
-
# defaults:
|
111
|
-
# migrate: true # Default --migrate choice for ey deploy
|
112
|
-
# migration_command: 'rake migrate' # Default migrate command to run when migrations are enabled
|
113
|
-
# branch: default_deploy_branch # Branch/ref to be deployed by default during ey deploy
|
114
|
-
# bundle_without: development test # The string to pass to bundle install --without ''
|
115
|
-
# maintenance_on_migrate: true # Enable maintenance page during migrate action (use with caution) (default: true)
|
116
|
-
# maintenance_on_restart: false # Enable maintanence page during every deploy (default: false for unicorn & passenger)
|
117
|
-
# ignore_database_adapter_warning: false # Hide the warning shown when the Gemfile does not contain a recognized database adapter (mongodb for example)
|
118
|
-
# your_own_custom_key: 'any attribute you put in ey.yml is available in deploy hooks'
|
119
|
-
# environments:
|
120
|
-
# YOUR_ENVIRONMENT_NAME: # All options pertain only to the named environment
|
121
|
-
# any_option: 'override any of the options above with specific options for certain environments'
|
122
|
-
# migrate: false
|
123
|
-
#
|
124
|
-
# Further information available here:
|
125
|
-
# https://support.cloud.engineyard.com/entries/20996661-customize-your-deployment-on-engine-yard-cloud
|
126
|
-
#
|
127
|
-
# NOTE: Please commit this file into your git repository.
|
128
|
-
#
|
129
|
-
HINTS
|
130
|
-
|
131
|
-
def ey_yml_comments
|
132
|
-
if @path.exist?
|
133
|
-
existing = @path.readlines.grep(/^#/).map {|line| line.strip }.join("\n")
|
134
|
-
else
|
135
|
-
EY_YML_HINTS
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def ensure_path
|
140
|
-
return if @path && @path.exist?
|
141
|
-
unless EY::Repo.exist?
|
142
|
-
raise "Not in application directory. Unable to save configuration."
|
143
|
-
end
|
144
|
-
if Pathname.new('config').exist?
|
145
|
-
@path = Pathname.new('config/ey.yml')
|
146
|
-
else
|
147
|
-
@path = Pathname.new('ey.yml')
|
148
|
-
end
|
149
|
-
@path
|
150
|
-
end
|
151
|
-
|
152
100
|
class EnvironmentConfig
|
153
101
|
attr_reader :name
|
154
102
|
|
@@ -162,28 +110,16 @@ module EY
|
|
162
110
|
@parent.path
|
163
111
|
end
|
164
112
|
|
165
|
-
def
|
166
|
-
|
167
|
-
|
113
|
+
def ensure_exists
|
114
|
+
unless path && path.exist?
|
115
|
+
raise EY::Error, "Please initialize this application with the following command:\n\tey init"
|
168
116
|
end
|
169
117
|
end
|
170
118
|
|
171
|
-
def
|
172
|
-
|
173
|
-
@parent.
|
174
|
-
else
|
175
|
-
@config[key.to_s] = val
|
176
|
-
@parent.set_environment_option(@name, key, val)
|
119
|
+
def fetch(key, default = nil, &block)
|
120
|
+
@config.fetch(key.to_s) do
|
121
|
+
@parent.fetch_from_defaults(key.to_s, default, &block)
|
177
122
|
end
|
178
|
-
val
|
179
|
-
end
|
180
|
-
|
181
|
-
def merge(other)
|
182
|
-
to_clean_hash.merge(other)
|
183
|
-
end
|
184
|
-
|
185
|
-
def to_clean_hash
|
186
|
-
@config.reject { |k,v| %w[branch migrate migration_command verbose].include?(k) }
|
187
123
|
end
|
188
124
|
|
189
125
|
def branch
|
@@ -191,22 +127,20 @@ module EY
|
|
191
127
|
end
|
192
128
|
|
193
129
|
def migrate
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
set('migrate', mig)
|
130
|
+
ensure_exists
|
131
|
+
fetch('migrate') do
|
132
|
+
raise EY::Error, "'migrate' not found in #{path}. Reinitialize with:\n\tey init"
|
133
|
+
end
|
199
134
|
end
|
200
135
|
|
201
136
|
def migration_command
|
202
|
-
|
137
|
+
ensure_exists
|
138
|
+
fetch('migration_command') do
|
139
|
+
raise EY::Error, "'migration_command' not found in #{path}. Reinitialize with:\n\tey init"
|
140
|
+
end
|
203
141
|
end
|
204
142
|
|
205
|
-
def migration_command=(cmd)
|
206
|
-
set('migration_command', cmd)
|
207
|
-
end
|
208
143
|
alias migrate_command migration_command
|
209
|
-
alias migrate_command= migration_command=
|
210
144
|
|
211
145
|
def verbose
|
212
146
|
fetch('verbose', false)
|