engineyard-serverside 1.6.0.pre5 → 1.6.3
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/lib/engineyard-serverside.rb +1 -3
- data/lib/engineyard-serverside/cli.rb +38 -73
- data/lib/engineyard-serverside/configuration.rb +12 -38
- data/lib/engineyard-serverside/deploy.rb +54 -63
- data/lib/engineyard-serverside/deploy_hook.rb +18 -21
- data/lib/engineyard-serverside/deprecation.rb +17 -9
- data/lib/engineyard-serverside/lockfile_parser.rb +1 -1
- data/lib/engineyard-serverside/logged_output.rb +91 -0
- data/lib/engineyard-serverside/rails_asset_support.rb +5 -5
- data/lib/engineyard-serverside/server.rb +11 -8
- data/lib/engineyard-serverside/strategies/git.rb +15 -12
- data/lib/engineyard-serverside/task.rb +8 -29
- data/lib/engineyard-serverside/version.rb +1 -1
- data/lib/vendor/systemu/LICENSE +3 -0
- data/lib/vendor/systemu/lib/systemu.rb +363 -0
- data/lib/vendor/systemu/systemu.gemspec +45 -0
- data/spec/basic_deploy_spec.rb +9 -9
- data/spec/bundler_deploy_spec.rb +1 -1
- data/spec/custom_deploy_spec.rb +4 -63
- data/spec/deploy_hook_spec.rb +78 -77
- data/spec/deprecation_spec.rb +26 -4
- data/spec/git_strategy_spec.rb +2 -6
- data/spec/logged_output_spec.rb +55 -0
- data/spec/nodejs_deploy_spec.rb +2 -2
- data/spec/services_deploy_spec.rb +10 -11
- data/spec/spec_helper.rb +25 -48
- data/spec/sqlite3_deploy_spec.rb +2 -1
- data/spec/support/integration.rb +14 -2
- metadata +79 -94
- data/lib/engineyard-serverside/shell.rb +0 -102
- data/lib/engineyard-serverside/shell/formatter.rb +0 -73
- data/lib/engineyard-serverside/shell/helpers.rb +0 -29
- data/lib/vendor/open4/lib/open4.rb +0 -432
- data/spec/shell_spec.rb +0 -50
@@ -1,51 +1,40 @@
|
|
1
|
-
require 'engineyard-serverside/shell/helpers'
|
2
|
-
|
3
1
|
module EY
|
4
2
|
module Serverside
|
5
3
|
class DeployHook < Task
|
4
|
+
def initialize(options)
|
5
|
+
super(EY::Serverside::Deploy::Configuration.new(options))
|
6
|
+
end
|
7
|
+
|
6
8
|
def callback_context
|
7
|
-
@context ||= CallbackContext.new(config
|
9
|
+
@context ||= CallbackContext.new(config)
|
8
10
|
end
|
9
11
|
|
10
12
|
def run(hook)
|
11
13
|
hook_path = "#{c.release_path}/deploy/#{hook}.rb"
|
12
14
|
if File.exist?(hook_path)
|
13
15
|
Dir.chdir(c.release_path) do
|
14
|
-
|
16
|
+
puts "~> running deploy hook: deploy/#{hook}.rb"
|
15
17
|
if desc = syntax_error(hook_path)
|
16
18
|
hook_name = File.basename(hook_path)
|
17
19
|
abort "*** [Error] Invalid Ruby syntax in hook: #{hook_name} ***\n*** #{desc.chomp} ***"
|
18
20
|
else
|
19
|
-
|
21
|
+
callback_context.instance_eval(IO.read(hook_path))
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
|
-
def eval_hook(code)
|
26
|
-
callback_context.instance_eval(code)
|
27
|
-
end
|
28
|
-
|
29
27
|
def syntax_error(file)
|
30
28
|
output = `ruby -c #{file} 2>&1`
|
31
29
|
output unless output =~ /Syntax OK/
|
32
30
|
end
|
33
31
|
|
34
32
|
class CallbackContext
|
35
|
-
|
36
|
-
|
37
|
-
attr_reader :shell
|
38
|
-
|
39
|
-
def initialize(config, shell)
|
33
|
+
def initialize(config)
|
40
34
|
@configuration = config
|
41
|
-
@shell = shell
|
42
35
|
@node = node
|
43
36
|
end
|
44
37
|
|
45
|
-
def config
|
46
|
-
@configuration
|
47
|
-
end
|
48
|
-
|
49
38
|
def method_missing(meth, *args, &blk)
|
50
39
|
if @configuration.respond_to?(meth)
|
51
40
|
@configuration.send(meth, *args, &blk)
|
@@ -59,11 +48,19 @@ module EY
|
|
59
48
|
end
|
60
49
|
|
61
50
|
def run(cmd)
|
62
|
-
|
51
|
+
system(Escape.shell_command(["sh", "-l", "-c", cmd]))
|
63
52
|
end
|
64
53
|
|
65
54
|
def sudo(cmd)
|
66
|
-
|
55
|
+
system(Escape.shell_command(["sudo", "sh", "-l", "-c", cmd]))
|
56
|
+
end
|
57
|
+
|
58
|
+
def info(*args)
|
59
|
+
$stderr.puts *args
|
60
|
+
end
|
61
|
+
|
62
|
+
def debug(*args)
|
63
|
+
$stdout.puts *args
|
67
64
|
end
|
68
65
|
|
69
66
|
# convenience functions for running on certain instance types
|
@@ -1,18 +1,26 @@
|
|
1
|
-
require 'engineyard-serverside/shell/helpers'
|
2
|
-
|
3
1
|
module EY
|
4
2
|
module Serverside
|
5
3
|
def self.deprecation_warning(msg)
|
6
4
|
$stderr.puts "DEPRECATION WARNING: #{msg}"
|
7
5
|
end
|
6
|
+
end
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
8
|
+
def self.const_missing(const)
|
9
|
+
if EY::Serverside.const_defined?(const)
|
10
|
+
EY::Serverside.deprecation_warning("EY::#{const} has been deprecated. use EY::Serverside::#{const} instead")
|
11
|
+
EY::Serverside.class_eval(const.to_s)
|
12
|
+
else
|
13
|
+
super
|
16
14
|
end
|
17
15
|
end
|
16
|
+
|
17
|
+
def self.node
|
18
|
+
EY::Serverside.deprecation_warning("EY.node has been deprecated. use EY::Serverside.node instead")
|
19
|
+
EY::Serverside.node
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.dna_json
|
23
|
+
EY::Serverside.deprecation_warning("EY.dna_json has been deprecated. use EY::Serverside.dna_json instead")
|
24
|
+
EY::Serverside.dna_json
|
25
|
+
end
|
18
26
|
end
|
@@ -24,7 +24,7 @@ module EY
|
|
24
24
|
@contents.index(/^\s+#{type}\s\([^\)]+\)$/)
|
25
25
|
end
|
26
26
|
|
27
|
-
any_jruby_adapter = %w[mysql postgresql].any? do |type|
|
27
|
+
any_jruby_adapter = %w[mysql postgresql postgres].any? do |type|
|
28
28
|
@contents.index(/^\s+jdbc-#{type}\s\([^\)]+\)$/) || @contents.index(/^\s+activerecord-jdbc#{type}-adapter\s\([^\)]+\)$/)
|
29
29
|
end
|
30
30
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'systemu'
|
2
|
+
|
3
|
+
module EY
|
4
|
+
module Serverside
|
5
|
+
module LoggedOutput
|
6
|
+
|
7
|
+
class Tee
|
8
|
+
def initialize(*streams)
|
9
|
+
@streams = streams.flatten
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(output)
|
13
|
+
@streams.each do |s|
|
14
|
+
s << output
|
15
|
+
s.flush
|
16
|
+
end
|
17
|
+
self
|
18
|
+
end
|
19
|
+
end # Tee
|
20
|
+
|
21
|
+
@@logfile = File.join(ENV['HOME'], 'ey.log')
|
22
|
+
def self.logfile=(filename)
|
23
|
+
File.unlink filename if File.exist?(filename) # start fresh
|
24
|
+
@@logfile = filename
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.logfile
|
28
|
+
@@logfile
|
29
|
+
end
|
30
|
+
|
31
|
+
@@verbose = false
|
32
|
+
def self.verbose=(v)
|
33
|
+
@@verbose = !!v
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.verbose?
|
37
|
+
@@verbose
|
38
|
+
end
|
39
|
+
|
40
|
+
def verbose?
|
41
|
+
EY::Serverside::LoggedOutput.verbose?
|
42
|
+
end
|
43
|
+
|
44
|
+
def warning(msg)
|
45
|
+
info "WARNING: #{msg}\n".gsub(/^/,'!> ')
|
46
|
+
end
|
47
|
+
|
48
|
+
def info(msg)
|
49
|
+
with_logfile do |log|
|
50
|
+
Tee.new($stdout, log) << ("#{with_timestamp(msg)}\n")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def debug(msg)
|
55
|
+
with_logfile do |log|
|
56
|
+
log << "#{with_timestamp(msg)}\n"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def logged_system(cmd)
|
61
|
+
with_logfile do |log|
|
62
|
+
out = verbose? ? Tee.new($stdout, log) : log
|
63
|
+
err = Tee.new($stderr, log) # we always want to see errors
|
64
|
+
|
65
|
+
cmd = "sh -c #{Escape.shell_command([cmd])}"
|
66
|
+
puts "running #{cmd}" if ENV['DEBUG']
|
67
|
+
out << with_timestamp(":: running #{cmd}\n")
|
68
|
+
status = systemu cmd, 'stdout' => out, 'stderr' => err
|
69
|
+
puts "exit status= #{status.exitstatus}" if ENV['DEBUG']
|
70
|
+
status.exitstatus == 0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def with_logfile
|
76
|
+
File.open(logfile, 'a') {|f| yield f }
|
77
|
+
end
|
78
|
+
|
79
|
+
def logfile
|
80
|
+
EY::Serverside::LoggedOutput.logfile
|
81
|
+
end
|
82
|
+
|
83
|
+
def with_timestamp(msg)
|
84
|
+
return msg unless respond_to?(:starting_time)
|
85
|
+
time_passed = Time.now.to_i - starting_time.to_i
|
86
|
+
timestamp = "+%2dm %02ds " % time_passed.divmod(60)
|
87
|
+
msg.gsub(/^/, timestamp)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -9,7 +9,7 @@ module EY
|
|
9
9
|
keep_existing_assets
|
10
10
|
cmd = "cd #{c.release_path} && PATH=#{c.binstubs_path}:$PATH #{c.framework_envs} rake assets:precompile || true"
|
11
11
|
if rails_version
|
12
|
-
|
12
|
+
info "~> Precompiling assets for rails v#{rails_version}"
|
13
13
|
else
|
14
14
|
warning "Precompiling assets even though Rails was not bundled."
|
15
15
|
end
|
@@ -22,24 +22,24 @@ module EY
|
|
22
22
|
return unless File.readable?(app_rb_path) # Not a Rails app in the first place.
|
23
23
|
|
24
24
|
if File.directory?(File.join(c.release_path, 'app', 'assets'))
|
25
|
-
|
25
|
+
info "~> app/assets/ found. Attempting Rails asset pre-compilation."
|
26
26
|
else
|
27
27
|
return false
|
28
28
|
end
|
29
29
|
|
30
30
|
if app_builds_own_assets?
|
31
|
-
|
31
|
+
info "~> public/assets already exists, skipping pre-compilation."
|
32
32
|
return
|
33
33
|
end
|
34
34
|
if app_disables_assets?(app_rb_path)
|
35
|
-
|
35
|
+
info "~> application.rb has disabled asset compilation. Skipping."
|
36
36
|
return
|
37
37
|
end
|
38
38
|
# This check is very expensive, and has been deemed not worth the time.
|
39
39
|
# Leaving this here in case someone comes up with a faster way.
|
40
40
|
=begin
|
41
41
|
unless app_has_asset_task?
|
42
|
-
|
42
|
+
info "~> No 'assets:precompile' Rake task found. Skipping."
|
43
43
|
return
|
44
44
|
end
|
45
45
|
=end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
require 'open-uri'
|
2
|
+
require 'engineyard-serverside/logged_output'
|
2
3
|
|
3
4
|
module EY
|
4
5
|
module Serverside
|
5
6
|
class Server < Struct.new(:hostname, :roles, :name, :user)
|
7
|
+
include LoggedOutput
|
8
|
+
|
6
9
|
class DuplicateHostname < StandardError
|
7
10
|
def initialize(hostname)
|
8
11
|
super "There is already an EY::Serverside::Server with hostname '#{hostname}'"
|
@@ -72,20 +75,20 @@ module EY
|
|
72
75
|
|
73
76
|
def sync_directory(directory)
|
74
77
|
return if local?
|
75
|
-
|
76
|
-
|
78
|
+
run "mkdir -p #{directory}"
|
79
|
+
logged_system(%|rsync --delete -aq -e "#{ssh_command}" #{directory}/ #{user}@#{hostname}:#{directory}|)
|
77
80
|
end
|
78
81
|
|
79
82
|
def run(command)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
if local?
|
84
|
+
logged_system(command)
|
85
|
+
else
|
86
|
+
logged_system("#{ssh_command} #{user}@#{hostname} #{Escape.shell_command [command]}")
|
87
|
+
end
|
85
88
|
end
|
86
89
|
|
87
90
|
def ssh_command
|
88
|
-
"ssh -i #{ENV['HOME']}/.ssh/internal -o StrictHostKeyChecking=no -o PasswordAuthentication=no
|
91
|
+
"ssh -i #{ENV['HOME']}/.ssh/internal -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o PasswordAuthentication=no"
|
89
92
|
end
|
90
93
|
|
91
94
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'engineyard-serverside/logged_output'
|
2
|
+
|
1
3
|
module EY
|
2
4
|
module Serverside
|
3
5
|
module Strategies
|
@@ -26,7 +28,7 @@ module EY
|
|
26
28
|
#
|
27
29
|
# Rollback doesn't know about the repository location (nor
|
28
30
|
# should it need to), but it would like to use #short_log_message.
|
29
|
-
klass.new(
|
31
|
+
klass.new(
|
30
32
|
:repository_cache => c[:repository_cache],
|
31
33
|
:app => c[:app],
|
32
34
|
:repo => c[:repo],
|
@@ -35,10 +37,11 @@ module EY
|
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
|
-
|
40
|
+
include LoggedOutput
|
41
|
+
|
42
|
+
attr_reader :opts
|
39
43
|
|
40
|
-
def initialize(
|
41
|
-
@shell = shell
|
44
|
+
def initialize(opts)
|
42
45
|
@opts = opts
|
43
46
|
end
|
44
47
|
|
@@ -48,21 +51,21 @@ module EY
|
|
48
51
|
|
49
52
|
def fetch
|
50
53
|
if usable_repository?
|
51
|
-
|
54
|
+
logged_system("#{git} fetch -q origin 2>&1")
|
52
55
|
else
|
53
56
|
FileUtils.rm_rf(opts[:repository_cache])
|
54
|
-
|
57
|
+
logged_system("git clone -q #{opts[:repo]} #{opts[:repository_cache]} 2>&1")
|
55
58
|
end
|
56
59
|
end
|
57
60
|
|
58
61
|
def checkout
|
59
|
-
|
62
|
+
info "~> Deploying revision #{short_log_message(to_checkout)}"
|
60
63
|
in_git_work_tree do
|
61
|
-
(
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
(logged_system("git checkout -q '#{to_checkout}'") ||
|
65
|
+
logged_system("git reset -q --hard '#{to_checkout}'")) &&
|
66
|
+
logged_system("git submodule sync") &&
|
67
|
+
logged_system("git submodule update --init") &&
|
68
|
+
logged_system("git clean -dfq")
|
66
69
|
end
|
67
70
|
end
|
68
71
|
|
@@ -1,16 +1,12 @@
|
|
1
|
-
require 'engineyard-serverside/shell/helpers'
|
2
|
-
|
3
1
|
module EY
|
4
2
|
module Serverside
|
5
3
|
class Task
|
6
|
-
include EY::Serverside::Shell::Helpers
|
7
4
|
|
8
|
-
attr_reader :config
|
5
|
+
attr_reader :config
|
9
6
|
alias :c :config
|
10
7
|
|
11
|
-
def initialize(conf
|
8
|
+
def initialize(conf)
|
12
9
|
@config = conf
|
13
|
-
@shell = shell
|
14
10
|
@roles = :all
|
15
11
|
end
|
16
12
|
|
@@ -22,7 +18,7 @@ module EY
|
|
22
18
|
end
|
23
19
|
|
24
20
|
if deploy_file
|
25
|
-
|
21
|
+
puts "~> Loading deployment task overrides from #{deploy_file}"
|
26
22
|
instance_eval(File.read(deploy_file))
|
27
23
|
true
|
28
24
|
else
|
@@ -30,25 +26,6 @@ module EY
|
|
30
26
|
end
|
31
27
|
end
|
32
28
|
|
33
|
-
def load_ey_yml
|
34
|
-
ey_yml = ["config/ey.yml", "ey.yml"].map do |short_file|
|
35
|
-
File.join(c.repository_cache, short_file)
|
36
|
-
end.detect do |file|
|
37
|
-
File.exist?(file)
|
38
|
-
end
|
39
|
-
|
40
|
-
if ey_yml
|
41
|
-
shell.status "Loading deploy configuration in #{ey_yml}"
|
42
|
-
data = YAML.load_file(ey_yml)
|
43
|
-
config.ey_yml_data = data
|
44
|
-
else
|
45
|
-
false
|
46
|
-
end
|
47
|
-
rescue Exception
|
48
|
-
shell.error "Error loading YAML in #{ey_yml}"
|
49
|
-
raise
|
50
|
-
end
|
51
|
-
|
52
29
|
def roles(*task_roles)
|
53
30
|
raise "Roles must be passed a block" unless block_given?
|
54
31
|
|
@@ -68,16 +45,18 @@ module EY
|
|
68
45
|
end
|
69
46
|
|
70
47
|
def sudo(cmd, &blk)
|
71
|
-
|
48
|
+
sudo_cmd = "sudo sh -c #{Escape.shell_command [cmd]}"
|
49
|
+
|
50
|
+
run_on_roles(sudo_cmd, &blk)
|
72
51
|
end
|
73
52
|
|
74
53
|
private
|
75
54
|
|
76
|
-
def run_on_roles(cmd,
|
55
|
+
def run_on_roles(cmd, &block)
|
77
56
|
servers = EY::Serverside::Server.from_roles(@roles)
|
78
57
|
futures = EY::Serverside::Future.call(servers, block_given?) do |server, exec_block|
|
79
58
|
to_run = exec_block ? block.call(server, cmd.dup) : cmd
|
80
|
-
server.run(
|
59
|
+
server.run(to_run)
|
81
60
|
end
|
82
61
|
|
83
62
|
unless EY::Serverside::Future.success?(futures)
|