foreplay 0.7.6 → 0.8.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 +4 -4
- data/.rubocop.yml +28 -25
- data/.ruby-version +1 -1
- data/foreplay.gemspec +12 -14
- data/lib/foreplay/cli.rb +42 -43
- data/lib/foreplay/engine/remote.rb +121 -0
- data/lib/foreplay/engine/role.rb +23 -0
- data/lib/foreplay/engine/server.rb +123 -0
- data/lib/foreplay/engine/step.rb +52 -0
- data/lib/foreplay/engine/steps.yml +75 -0
- data/lib/foreplay/engine.rb +138 -0
- data/lib/foreplay/foreplay.rb +10 -0
- data/lib/foreplay/launcher.rb +13 -0
- data/lib/foreplay/setup.rb +24 -26
- data/lib/foreplay/version.rb +1 -1
- data/lib/foreplay.rb +7 -3
- data/lib/string.rb +17 -0
- data/spec/lib/foreplay/deploy_spec.rb +79 -24
- data/spec/lib/foreplay/engine_spec.rb +32 -0
- data/spec/lib/foreplay/setup_spec.rb +1 -1
- metadata +47 -60
- data/lib/foreplay/deploy.rb +0 -395
- data/lib/foreplay/utility.rb +0 -30
- data/spec/lib/foreplay/utility_spec.rb +0 -28
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9a1dbd3b362d4784a5b5878bba559b812106e9c8
|
|
4
|
+
data.tar.gz: fe058cb4c473892115225f78587d0f88929bc745
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 08f86cc7dfb91d26d9865dbfdcd05adf603e1f5afa690e51503215b2005ed3c93982fca7b798589b6de490184f0a3ddd875a6068ce14ed00b0ba1c871065b4cc
|
|
7
|
+
data.tar.gz: 3d360c7d1ab0a3fdd61d25eaa46d6da0ba38f88df993daa78ac180f57979d43e9073390de2842abb566d63028cf3c6238ad151a69b1c7a37c5ebe8a6384d4974
|
data/.rubocop.yml
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
# These are OK:
|
|
3
|
+
|
|
2
4
|
StringLiterals:
|
|
3
5
|
EnforcedStyle: single_quotes
|
|
4
6
|
Enabled: true
|
|
@@ -6,44 +8,45 @@ StringLiterals:
|
|
|
6
8
|
DotPosition:
|
|
7
9
|
Description: 'Checks the position of the dot in multi-line method calls.'
|
|
8
10
|
EnforcedStyle: leading
|
|
9
|
-
# EnforcedStyle: trailing
|
|
10
11
|
Enabled: true
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
Description: '
|
|
14
|
-
|
|
13
|
+
ClassAndModuleChildren:
|
|
14
|
+
Description: 'Checks style of children classes and modules.'
|
|
15
|
+
EnforcedStyle: compact
|
|
15
16
|
Enabled: true
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
Description: '
|
|
18
|
+
Documentation:
|
|
19
|
+
Description: 'Document classes and non-namespace modules.'
|
|
19
20
|
Enabled: false
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
Description: '
|
|
22
|
+
Output:
|
|
23
|
+
Description: 'Checks for calls to puts, print, etc.'
|
|
23
24
|
Enabled: false
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
Description: 'Document classes and non-namespace modules.'
|
|
26
|
+
ExtraSpacing:
|
|
27
27
|
Enabled: false
|
|
28
28
|
|
|
29
|
+
FileName:
|
|
30
|
+
Description: 'Use snake_case for source file names.'
|
|
31
|
+
Enabled: true
|
|
32
|
+
|
|
33
|
+
# Work on these:
|
|
34
|
+
|
|
35
|
+
LineLength:
|
|
36
|
+
Description: 'Limit lines to 137 characters.'
|
|
37
|
+
Max: 120
|
|
38
|
+
Enabled: true
|
|
39
|
+
|
|
40
|
+
MethodLength:
|
|
41
|
+
Description: 'Avoid methods longer than 10 lines of code.'
|
|
42
|
+
Max: 27 # 85
|
|
43
|
+
|
|
29
44
|
CyclomaticComplexity:
|
|
30
45
|
Description: 'Avoid complex methods.'
|
|
31
|
-
Max:
|
|
46
|
+
Max: 9
|
|
32
47
|
|
|
33
48
|
PerceivedComplexity:
|
|
34
|
-
Max: 17
|
|
35
|
-
|
|
36
|
-
ClassLength:
|
|
37
|
-
Description: 'Avoid classes longer than 100 lines of code.'
|
|
38
|
-
CountComments: false # count full line comments?
|
|
39
|
-
Max: 295
|
|
40
|
-
|
|
41
|
-
Output:
|
|
42
|
-
Description: 'Checks for calls to puts, print, etc.'
|
|
43
|
-
Enabled: false
|
|
49
|
+
Max: 11 # 17
|
|
44
50
|
|
|
45
51
|
AbcSize:
|
|
46
|
-
Max: 62
|
|
47
|
-
|
|
48
|
-
ExtraSpacing:
|
|
49
|
-
Enabled: false
|
|
52
|
+
Max: 48 # 62
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.2.
|
|
1
|
+
2.2.2
|
data/foreplay.gemspec
CHANGED
|
@@ -8,28 +8,26 @@ Gem::Specification.new do |spec|
|
|
|
8
8
|
spec.authors = ['Xenapto']
|
|
9
9
|
spec.email = ['developers@xenapto.com']
|
|
10
10
|
spec.description = 'Deploying Rails projects to Ubuntu using Foreman'
|
|
11
|
-
spec.summary = 'Example: foreplay
|
|
11
|
+
spec.summary = 'Example: foreplay deploy production'
|
|
12
12
|
spec.homepage = 'https://github.com/Xenapto/foreplay'
|
|
13
13
|
spec.license = 'MIT'
|
|
14
14
|
|
|
15
15
|
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
|
16
|
-
spec.executables = spec.files.grep(
|
|
17
|
-
spec.test_files = spec.files.grep(
|
|
16
|
+
spec.executables = spec.files.grep(%r{^bin\/}) { |f| File.basename(f) }
|
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features|coverage)\/})
|
|
18
18
|
spec.require_paths = ['lib']
|
|
19
19
|
|
|
20
20
|
spec.add_runtime_dependency 'activesupport', '>= 3.2'
|
|
21
|
-
spec.add_runtime_dependency 'colorize', '>= 0.7'
|
|
22
21
|
spec.add_runtime_dependency 'foreman', '>= 0.76'
|
|
23
22
|
spec.add_runtime_dependency 'ssh-shell', '>= 0.4'
|
|
24
|
-
# spec.add_runtime_dependency 'thor', '~> 0.19' # Dependency of foreman anyway
|
|
25
23
|
|
|
26
|
-
spec.add_development_dependency 'bundler', '
|
|
27
|
-
spec.add_development_dependency 'rake', '
|
|
28
|
-
spec.add_development_dependency 'rspec', '
|
|
29
|
-
spec.add_development_dependency 'cucumber', '
|
|
30
|
-
spec.add_development_dependency 'aruba', '
|
|
31
|
-
spec.add_development_dependency 'gem-release', '
|
|
32
|
-
spec.add_development_dependency 'simplecov', '
|
|
33
|
-
spec.add_development_dependency 'coveralls', '
|
|
34
|
-
spec.add_development_dependency 'rubocop', '
|
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.9'
|
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.4'
|
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.2'
|
|
27
|
+
spec.add_development_dependency 'cucumber', '~> 2.0'
|
|
28
|
+
spec.add_development_dependency 'aruba', '~> 0.6'
|
|
29
|
+
spec.add_development_dependency 'gem-release', '~> 0.7'
|
|
30
|
+
spec.add_development_dependency 'simplecov', '~> 0.10'
|
|
31
|
+
spec.add_development_dependency 'coveralls', '~> 0.8'
|
|
32
|
+
spec.add_development_dependency 'rubocop', '~> 0.30'
|
|
35
33
|
end
|
data/lib/foreplay/cli.rb
CHANGED
|
@@ -1,48 +1,47 @@
|
|
|
1
1
|
require 'thor'
|
|
2
2
|
require 'foreplay'
|
|
3
|
+
require 'foreplay/setup'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
Foreplay::Setup.start
|
|
46
|
-
end
|
|
5
|
+
class Foreplay::CLI < Thor
|
|
6
|
+
desc 'deploy ENVIRONMENT', 'Deploys to specified environment'
|
|
7
|
+
|
|
8
|
+
method_option :role, aliases: '-r'
|
|
9
|
+
method_option :server, aliases: '-s'
|
|
10
|
+
|
|
11
|
+
def deploy(environment)
|
|
12
|
+
Foreplay::Launcher.start [:deploy, environment, options]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
desc 'check ENVIRONMENT', 'Checks if configuration is OK for specified environment'
|
|
16
|
+
|
|
17
|
+
method_option :role, aliases: '-r'
|
|
18
|
+
method_option :server, aliases: '-s'
|
|
19
|
+
|
|
20
|
+
def check(environment)
|
|
21
|
+
Foreplay::Launcher.start [:check, environment, options]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
desc 'setup', 'Create the Foreplay config file'
|
|
25
|
+
|
|
26
|
+
method_option :name, aliases: '-n'
|
|
27
|
+
method_option :repository, aliases: '-r'
|
|
28
|
+
method_option :user, aliases: '-u'
|
|
29
|
+
method_option :password
|
|
30
|
+
method_option :keyfile
|
|
31
|
+
method_option :private_key, aliases: '-k'
|
|
32
|
+
method_option :path, aliases: '-f'
|
|
33
|
+
method_option :port, aliases: '-p', type: :numeric
|
|
34
|
+
method_option :servers, aliases: '-s', type: :array
|
|
35
|
+
method_option :db_adapter, aliases: '-a'
|
|
36
|
+
method_option :db_encoding, aliases: '-e'
|
|
37
|
+
method_option :db_name, aliases: '-d'
|
|
38
|
+
method_option :db_pool, type: :numeric
|
|
39
|
+
method_option :db_host, aliases: '-h'
|
|
40
|
+
method_option :db_user
|
|
41
|
+
method_option :db_password
|
|
42
|
+
method_option :resque_redis
|
|
43
|
+
|
|
44
|
+
def setup
|
|
45
|
+
Foreplay::Setup.start
|
|
47
46
|
end
|
|
48
47
|
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require 'net/ssh'
|
|
2
|
+
|
|
3
|
+
class Foreplay::Engine::Remote
|
|
4
|
+
include Foreplay
|
|
5
|
+
attr_reader :server, :steps, :instructions
|
|
6
|
+
|
|
7
|
+
def initialize(s, st, i)
|
|
8
|
+
@server = s
|
|
9
|
+
@steps = st
|
|
10
|
+
@instructions = i
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def deploy
|
|
14
|
+
output = ''
|
|
15
|
+
|
|
16
|
+
puts "#{host}#{INDENT}Connecting to #{host} on port #{port}"
|
|
17
|
+
|
|
18
|
+
# SSH connection
|
|
19
|
+
session = start_session(host, user, options)
|
|
20
|
+
|
|
21
|
+
puts "#{host}#{INDENT}Successfully connected to #{host} on port #{port}"
|
|
22
|
+
|
|
23
|
+
session.shell do |sh|
|
|
24
|
+
steps.each do |step|
|
|
25
|
+
puts "#{host}#{INDENT}#{(step['commentary'] || step['command']).yellow}" unless step['silent'] == true
|
|
26
|
+
|
|
27
|
+
# Output from this step
|
|
28
|
+
output = ''
|
|
29
|
+
previous = '' # We don't need or want the final CRLF
|
|
30
|
+
commands = Foreplay::Engine::Step.new(step, instructions).build
|
|
31
|
+
|
|
32
|
+
commands.each do |command|
|
|
33
|
+
process = sh.execute command
|
|
34
|
+
|
|
35
|
+
process.on_output do |_, o|
|
|
36
|
+
previous = o
|
|
37
|
+
output += previous
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
sh.wait!
|
|
41
|
+
|
|
42
|
+
if step['ignore_error'] == true || process.exit_status == 0
|
|
43
|
+
print output.gsub!(/^/, "#{host}#{INDENT * 2}") unless step['silent'] == true || output.blank?
|
|
44
|
+
else
|
|
45
|
+
terminate(output)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
session.close
|
|
52
|
+
output
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Deployment check: just say what we would have done
|
|
56
|
+
def check
|
|
57
|
+
steps.each do |step|
|
|
58
|
+
puts "#{host}#{INDENT}#{(step['commentary'] || step['command']).yellow}" unless step['silent'] == true
|
|
59
|
+
commands = Foreplay::Engine::Step.new(step, instructions).build
|
|
60
|
+
commands.each { |command| puts "#{host}#{INDENT * 2}#{command}" unless step['silent'] }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
''
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def user
|
|
67
|
+
@user = instructions[:user]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def host
|
|
71
|
+
@host ||= host_port[0]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def port
|
|
75
|
+
@port ||= (host_port[1] || 22)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def host_port
|
|
79
|
+
@host_port ||= server.split(':') # Parse host + port
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def options
|
|
83
|
+
return @options if @options
|
|
84
|
+
|
|
85
|
+
password = instructions[:password]
|
|
86
|
+
keyfile = instructions[:keyfile]
|
|
87
|
+
private_key = instructions[:private_key]
|
|
88
|
+
|
|
89
|
+
keyfile.sub! '~', ENV['HOME'] || '/' unless keyfile.blank? # Remote shell won't expand this for us
|
|
90
|
+
|
|
91
|
+
# SSH authentication methods
|
|
92
|
+
@options = { verbose: :warn, port: port }
|
|
93
|
+
|
|
94
|
+
if password.blank?
|
|
95
|
+
# If there's no password we must supply a private key
|
|
96
|
+
if private_key.blank?
|
|
97
|
+
message = 'No authentication methods supplied. '\
|
|
98
|
+
'You must supply a private key, key file or password in the configuration file'
|
|
99
|
+
terminate(message) if keyfile.blank?
|
|
100
|
+
# Get the key from the key file
|
|
101
|
+
puts "#{INDENT}Using private key from #{keyfile}"
|
|
102
|
+
private_key = File.read keyfile
|
|
103
|
+
else
|
|
104
|
+
puts "#{INDENT}Using private key from the configuration file"
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
@options[:key_data] = [private_key]
|
|
108
|
+
else
|
|
109
|
+
# Use the password supplied
|
|
110
|
+
@options[:password] = password
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
@options
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def start_session(host, user, options)
|
|
117
|
+
Net::SSH.start(host, user, options)
|
|
118
|
+
rescue SocketError => e
|
|
119
|
+
terminate "#{host}#{INDENT}There was a problem starting an ssh session on #{host}:\n#{e.message}"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class Foreplay::Engine::Role
|
|
2
|
+
attr_reader :environment, :mode, :instructions, :servers
|
|
3
|
+
|
|
4
|
+
def initialize(e, m, i)
|
|
5
|
+
@environment = e
|
|
6
|
+
@mode = m
|
|
7
|
+
@instructions = i
|
|
8
|
+
@servers = @instructions[:servers]
|
|
9
|
+
|
|
10
|
+
preposition = mode == :deploy ? 'to' : 'for'
|
|
11
|
+
|
|
12
|
+
return if @servers.length == 1
|
|
13
|
+
|
|
14
|
+
puts "#{mode.capitalize}ing #{instructions[:name].yellow} #{preposition} #{@servers.join(', ').yellow} "\
|
|
15
|
+
"for the #{instructions[:role].dup.yellow} role in the #{environment.dup.yellow} environment..."
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def threads
|
|
19
|
+
servers.map do |server|
|
|
20
|
+
Thread.new { Foreplay::Engine::Server.new(environment, mode, instructions, server).execute }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'active_support/inflector'
|
|
2
|
+
|
|
3
|
+
class Foreplay::Engine::Server
|
|
4
|
+
include Foreplay
|
|
5
|
+
attr_reader :environment, :mode, :instructions, :server
|
|
6
|
+
|
|
7
|
+
def initialize(e, m, i, s)
|
|
8
|
+
@environment = e
|
|
9
|
+
@mode = m
|
|
10
|
+
@instructions = i
|
|
11
|
+
@server = s
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def execute
|
|
15
|
+
preposition = mode == :deploy ? 'to' : 'for'
|
|
16
|
+
|
|
17
|
+
message = "#{mode.capitalize}ing #{name.yellow} #{preposition} #{host.yellow} "
|
|
18
|
+
message += "for the #{role.dup.yellow} role in the #{environment.dup.yellow} environment"
|
|
19
|
+
puts message
|
|
20
|
+
|
|
21
|
+
instructions[:foreman]['app'] = current_service
|
|
22
|
+
instructions[:foreman]['port'] = current_port
|
|
23
|
+
instructions[:foreman]['user'] = user
|
|
24
|
+
instructions[:foreman]['log'] = "$HOME/#{path}/#{current_port}/log"
|
|
25
|
+
|
|
26
|
+
# Contents of .env file
|
|
27
|
+
instructions[:env]['HOME'] = '$HOME'
|
|
28
|
+
instructions[:env]['SHELL'] = '$SHELL'
|
|
29
|
+
instructions[:env]['PATH'] = '$PATH:`which bundle`'
|
|
30
|
+
|
|
31
|
+
Foreplay::Engine::Remote.new(server, steps, instructions).__send__ mode
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def role
|
|
35
|
+
@role ||= instructions[:role]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def user
|
|
39
|
+
@user ||= instructions[:user]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def name
|
|
43
|
+
@name ||= instructions[:name]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def path
|
|
47
|
+
return @path if @path
|
|
48
|
+
|
|
49
|
+
@path = instructions[:path]
|
|
50
|
+
@path.gsub! '%u', user
|
|
51
|
+
@path.gsub! '%a', name
|
|
52
|
+
@path
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def host
|
|
56
|
+
return @host if @host
|
|
57
|
+
@host, _ = server.split(':') # Parse host + port
|
|
58
|
+
@host
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def steps
|
|
62
|
+
@steps ||= YAML.load(
|
|
63
|
+
ERB.new(
|
|
64
|
+
File.read(
|
|
65
|
+
"#{File.dirname(__FILE__)}/steps.yml"
|
|
66
|
+
)
|
|
67
|
+
).result(binding)
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def current_port
|
|
72
|
+
@current_port ||= port_details[:current_port]
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def current_service
|
|
76
|
+
@current_service ||= port_details[:current_service]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def former_port
|
|
80
|
+
@former_port ||= port_details[:former_port]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def former_service
|
|
84
|
+
@former_service ||= port_details[:former_service]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def current_port_file
|
|
88
|
+
@current_port_file ||= ".foreplay/#{name}/current_port"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def port_steps
|
|
92
|
+
@port_steps ||= [
|
|
93
|
+
{
|
|
94
|
+
'command' => "mkdir -p .foreplay/#{name} && touch #{current_port_file} && cat #{current_port_file}",
|
|
95
|
+
'silent' => true
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def port_details
|
|
101
|
+
return @port_details if @port_details
|
|
102
|
+
|
|
103
|
+
current_port_string = Foreplay::Engine::Remote.new(server, port_steps, instructions).__send__(mode).strip!
|
|
104
|
+
|
|
105
|
+
if current_port_string.blank?
|
|
106
|
+
puts "#{host}#{INDENT}No instance is currently deployed"
|
|
107
|
+
else
|
|
108
|
+
puts "#{host}#{INDENT}Current instance is using port #{current_port_string}"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
cp = current_port_string.to_i
|
|
112
|
+
port = instructions[:port]
|
|
113
|
+
ports = [port + 1000, port]
|
|
114
|
+
cp, fp = cp == port ? ports : ports.reverse
|
|
115
|
+
|
|
116
|
+
@port_details = {
|
|
117
|
+
current_port: cp,
|
|
118
|
+
current_service: "#{name}-#{cp}",
|
|
119
|
+
former_port: fp,
|
|
120
|
+
former_service: "#{name}-#{fp}"
|
|
121
|
+
}
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
class Foreplay::Engine::Step
|
|
2
|
+
attr_reader :step, :instructions
|
|
3
|
+
|
|
4
|
+
def initialize(s, i)
|
|
5
|
+
@step = s
|
|
6
|
+
@instructions = i
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def build
|
|
10
|
+
# Each step can be (1) a command or (2) a series of values to add to a file
|
|
11
|
+
if step.key?('key')
|
|
12
|
+
instructions.key?(step['key']) ? build_commands(step, instructions) : []
|
|
13
|
+
else
|
|
14
|
+
# ...or just execute the command specified
|
|
15
|
+
[step['command']]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def build_commands(step, instructions)
|
|
20
|
+
# Add values from the config file to a file on the remote machine
|
|
21
|
+
key = step['key']
|
|
22
|
+
prefix = step['prefix'] || ''
|
|
23
|
+
suffix = step['suffix'] || ''
|
|
24
|
+
path = step['path'] || ''
|
|
25
|
+
before = step['before'] || ''
|
|
26
|
+
delimiter = step['delimiter'] || ''
|
|
27
|
+
after = step['after'] || ''
|
|
28
|
+
|
|
29
|
+
step['silent'] = true
|
|
30
|
+
filename = "#{path}#{prefix}#{key}#{suffix}"
|
|
31
|
+
|
|
32
|
+
if step.key?('header')
|
|
33
|
+
commands = ["echo \"#{step['header']}\" > #{filename}"]
|
|
34
|
+
redirect = '>>'
|
|
35
|
+
else
|
|
36
|
+
commands = []
|
|
37
|
+
redirect = '>'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if instructions[key].is_a? Hash
|
|
41
|
+
instructions[key].each do |k, v|
|
|
42
|
+
commands << "echo \"#{before}#{k}#{delimiter}#{v}#{after}\" #{redirect} #{filename}"
|
|
43
|
+
redirect = '>>'
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
commands << "echo \"#{before}#{delimiter}#{instructions[key]}#{after}\" #{redirect} #{filename}"
|
|
47
|
+
redirect = '>>'
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
commands
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
- command: "echo Foreplay version <%= VERSION %>"
|
|
3
|
+
commentary: "Foreplay running from <%= `hostname -f` %><%= `which foreman` %>"
|
|
4
|
+
- command: "mkdir -p <%= path %> && cd <%= path %> && rm -rf <%= current_port %> && git clone -b <%= instructions[:branch] || 'master' %> <%= instructions[:repository] %> <%= current_port %>"
|
|
5
|
+
commentary: "Cloning <%= instructions[:branch] || 'master' %> branch of repository <%= instructions[:repository] %>"
|
|
6
|
+
- command: "rvm rvmrc trust <%= current_port %>"
|
|
7
|
+
commentary: 'Trusting the .rvmrc file for the new instance'
|
|
8
|
+
- command: "rvm rvmrc warning ignore <%= current_port %>"
|
|
9
|
+
commentary: 'Ignoring the .rvmrc warning for the new instance'
|
|
10
|
+
- command: 'gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys D39DC0E3'
|
|
11
|
+
commentary: "Trusting RVM's public key"
|
|
12
|
+
ignore_error: true
|
|
13
|
+
- command: "cd <%= current_port %> && mkdir -p tmp doc log config"
|
|
14
|
+
commentary: 'If you have a .rvmrc file there may be a delay now while we install a new ruby'
|
|
15
|
+
- command: 'if [ -f .ruby-version ] ; then rvm install `cat .ruby-version` ; else echo "No .ruby-version file found" ; fi'
|
|
16
|
+
commentary: 'If you have a .ruby-version file there may be a delay now while we install a new ruby'
|
|
17
|
+
- key: :env
|
|
18
|
+
delimiter: '='
|
|
19
|
+
prefix: '.'
|
|
20
|
+
commentary: 'Building .env'
|
|
21
|
+
- key: :foreman
|
|
22
|
+
delimiter: ': '
|
|
23
|
+
prefix: '.'
|
|
24
|
+
commentary: 'Building .foreman'
|
|
25
|
+
- key: :database
|
|
26
|
+
delimiter: ': '
|
|
27
|
+
suffix: '.yml'
|
|
28
|
+
commentary: 'Building config/database.yml'
|
|
29
|
+
before: ' '
|
|
30
|
+
header: "<%= environment %>:"
|
|
31
|
+
path: 'config/'
|
|
32
|
+
- key: :resque
|
|
33
|
+
delimiter: ': '
|
|
34
|
+
suffix: '.yml'
|
|
35
|
+
commentary: 'Building config/resque.yml'
|
|
36
|
+
before: environment
|
|
37
|
+
path: 'config/'
|
|
38
|
+
- command: 'if [ -d ../cache/vendor/bundle/bundle ] ; then rm -rf ../cache/vendor/bundle/bundle ; else echo No evidence of legacy copy bug ; fi'
|
|
39
|
+
commentary: 'Fixing legacy copy bug'
|
|
40
|
+
- command: 'if [ -d ../cache/vendor/bundle ] ; then rsync -aW --no-compress --delete --info=STATS1 ../cache/vendor/bundle/ vendor/bundle ; else echo No bundle to restore ; fi'
|
|
41
|
+
commentary: 'Attempting to restore bundle from cache'
|
|
42
|
+
- command: 'sudo ln -f `which bundle` /usr/bin/bundle || echo Using default version of bundle'
|
|
43
|
+
commentary: 'Setting the current version of bundle to be the default'
|
|
44
|
+
- command: 'bundle install --deployment --clean --jobs 2 --without development test'
|
|
45
|
+
commentary: 'Using bundler to install the required gems in deployment mode'
|
|
46
|
+
- command: 'mkdir -p ../cache/vendor && rsync -aW --no-compress --delete --info=STATS1 vendor/bundle/ ../cache/vendor/bundle'
|
|
47
|
+
commentary: 'Caching bundle'
|
|
48
|
+
- command: 'if [ -f public/assets/manifest.yml ] ; then echo "Not precompiling assets" ; else RAILS_ENV=<%= environment %> bundle exec foreman run rake assets:precompile ; fi'
|
|
49
|
+
commentary: 'Precompiling assets unless they were supplied'
|
|
50
|
+
- command: 'sudo bundle exec foreman export upstart /etc/init'
|
|
51
|
+
commentary: "Converting <%= current_service %> to an upstart service"
|
|
52
|
+
- command: "sudo start <%= current_service %> || sudo restart <%= current_service %>"
|
|
53
|
+
commentary: 'Starting the service'
|
|
54
|
+
ignore_error: true
|
|
55
|
+
- command: "echo <%= current_port %> > $HOME/<%= current_port_file %>"
|
|
56
|
+
commentary: "Setting the port for the new instance to <%= current_port %>"
|
|
57
|
+
- command: 'sleep 60'
|
|
58
|
+
commentary: 'Waiting 60s to give service time to start'
|
|
59
|
+
- command: "sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port <%= current_port %>"
|
|
60
|
+
commentary: "Adding firewall rule to direct incoming traffic on port 80 to port <%= current_port %>"
|
|
61
|
+
- command: "sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port <%= former_port %>"
|
|
62
|
+
commentary: "Removing previous firewall rule directing traffic to port <%= former_port %>"
|
|
63
|
+
ignore_error: true
|
|
64
|
+
- command: 'sudo iptables-save > /etc/iptables/rules.v4'
|
|
65
|
+
commentary: 'Attempting to save firewall rules to /etc/iptables/rules.v4'
|
|
66
|
+
ignore_error: true
|
|
67
|
+
- command: 'sudo iptables-save > /etc/iptables.up.rules'
|
|
68
|
+
commentary: 'Attempting to save firewall rules to /etc/iptables.up.rules'
|
|
69
|
+
ignore_error: true
|
|
70
|
+
- command: 'sudo iptables-save -c | egrep REDIRECT --color=never'
|
|
71
|
+
ignore_error: true
|
|
72
|
+
commentary: 'Current firewall NAT configuration:'
|
|
73
|
+
- command: "sudo stop <%= former_service %> || echo 'No previous instance running'"
|
|
74
|
+
commentary: 'Stopping the previous instance'
|
|
75
|
+
ignore_error: true
|