foreplay 0.9.13 → 0.10.1
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/.gitignore +2 -0
- data/.rubocop.yml +1 -1
- data/lib/foreplay/cli.rb +47 -45
- data/lib/foreplay/engine/defaults.rb +60 -0
- data/lib/foreplay/engine/logger.rb +50 -46
- data/lib/foreplay/engine/port.rb +65 -60
- data/lib/foreplay/engine/remote/check.rb +44 -38
- data/lib/foreplay/engine/remote/step.rb +34 -28
- data/lib/foreplay/engine/remote.rb +93 -86
- data/lib/foreplay/engine/role.rb +19 -15
- data/lib/foreplay/engine/secrets.rb +28 -24
- data/lib/foreplay/engine/server.rb +66 -55
- data/lib/foreplay/engine/step.rb +100 -96
- data/lib/foreplay/engine.rb +57 -106
- data/lib/foreplay/launcher.rb +9 -7
- data/lib/foreplay/setup.rb +26 -24
- data/lib/foreplay/version.rb +1 -1
- data/lib/foreplay.rb +14 -11
- data/spec/lib/foreplay/deploy_spec.rb +6 -2
- metadata +3 -4
- data/foreplay.rake +0 -28
- data/lib/foreplay/foreplay.rb +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 35a3ae418413c4a78a0c33ef41eb5e7168287e32
|
|
4
|
+
data.tar.gz: 954d074b1b34dc7643b3cd4a3b8daa433fa74ad1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 20fd2bc4dc6f9eae22d3c098425b581d7b53d19bb0a1085ef8263edcb54b8bbd6f61b98f91ae78034d393316231203c97a90308b9f98cfc4c95af63569b8ddd8
|
|
7
|
+
data.tar.gz: aa5ad1cdc055544d768d7ffd63e2dd7766f5eddc23103ea4ab90c8a131efdb8d9b662a4e74e02a770856900c477d337123a8d2f2289797b24959b6a06a10bced
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/lib/foreplay/cli.rb
CHANGED
|
@@ -2,50 +2,52 @@ require 'thor'
|
|
|
2
2
|
require 'foreplay'
|
|
3
3
|
require 'foreplay/setup'
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
5
|
+
module Foreplay
|
|
6
|
+
class CLI < Thor
|
|
7
|
+
desc 'deploy ENVIRONMENT', 'Deploys to specified environment'
|
|
8
|
+
|
|
9
|
+
method_option :role, aliases: '-r'
|
|
10
|
+
method_option :server, aliases: '-s'
|
|
11
|
+
method_option :config_file, aliases: '-f'
|
|
12
|
+
method_option :verbose, aliases: '-v'
|
|
13
|
+
|
|
14
|
+
def deploy(environment)
|
|
15
|
+
Foreplay::Launcher.start [:deploy, environment, options]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc 'check ENVIRONMENT', 'Checks if configuration is OK for specified environment'
|
|
19
|
+
|
|
20
|
+
method_option :role, aliases: '-r'
|
|
21
|
+
method_option :server, aliases: '-s'
|
|
22
|
+
method_option :config_file, aliases: '-f'
|
|
23
|
+
method_option :verbose, aliases: '-v'
|
|
24
|
+
|
|
25
|
+
def check(environment)
|
|
26
|
+
Foreplay::Launcher.start [:check, environment, options]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
desc 'setup', 'Create the Foreplay config file'
|
|
30
|
+
|
|
31
|
+
method_option :name, aliases: '-n'
|
|
32
|
+
method_option :repository, aliases: '-r'
|
|
33
|
+
method_option :user, aliases: '-u'
|
|
34
|
+
method_option :password
|
|
35
|
+
method_option :keyfile
|
|
36
|
+
method_option :private_key, aliases: '-k'
|
|
37
|
+
method_option :path, aliases: '-f'
|
|
38
|
+
method_option :port, aliases: '-p', type: :numeric
|
|
39
|
+
method_option :servers, aliases: '-s', type: :array
|
|
40
|
+
method_option :db_adapter, aliases: '-a'
|
|
41
|
+
method_option :db_encoding, aliases: '-e'
|
|
42
|
+
method_option :db_name, aliases: '-d'
|
|
43
|
+
method_option :db_pool, type: :numeric
|
|
44
|
+
method_option :db_host, aliases: '-h'
|
|
45
|
+
method_option :db_user
|
|
46
|
+
method_option :db_password
|
|
47
|
+
method_option :resque_redis
|
|
48
|
+
|
|
49
|
+
def setup
|
|
50
|
+
Foreplay::Setup.start
|
|
51
|
+
end
|
|
50
52
|
end
|
|
51
53
|
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Foreplay
|
|
2
|
+
class Engine
|
|
3
|
+
module Defaults
|
|
4
|
+
include Foreplay
|
|
5
|
+
|
|
6
|
+
DEFAULT_CONFIG_FILE = "#{Dir.getwd}/config/foreplay.yml"
|
|
7
|
+
DEFAULTS_KEY = 'defaults'
|
|
8
|
+
|
|
9
|
+
def defaults
|
|
10
|
+
return @defaults if @defaults
|
|
11
|
+
|
|
12
|
+
# Establish defaults
|
|
13
|
+
# First the default defaults
|
|
14
|
+
@defaults = {
|
|
15
|
+
'name' => File.basename(Dir.getwd),
|
|
16
|
+
'environment' => environment,
|
|
17
|
+
'port' => DEFAULT_PORT
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@defaults['env'] = secrets
|
|
21
|
+
@defaults['application'] = secrets
|
|
22
|
+
@defaults = @defaults.supermerge(roles_all[DEFAULTS_KEY]) if roles_all.key? DEFAULTS_KEY
|
|
23
|
+
@defaults = @defaults.supermerge(roles[DEFAULTS_KEY]) if roles.key? DEFAULTS_KEY
|
|
24
|
+
@defaults
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Secret environment variables
|
|
28
|
+
def secrets
|
|
29
|
+
@secrets ||= (Foreplay::Engine::Secrets.new(environment, roles_all['secrets']).fetch || {})
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def roles
|
|
33
|
+
@roles ||= roles_all[environment]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def roles_all
|
|
37
|
+
return @roles_all if @roles_all
|
|
38
|
+
|
|
39
|
+
@roles_all = YAML.load(File.read(config_file))
|
|
40
|
+
|
|
41
|
+
# This environment
|
|
42
|
+
unless @roles_all.key? environment
|
|
43
|
+
terminate("No deployment configuration defined for #{environment} environment.\nCheck #{config_file}")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@roles_all
|
|
47
|
+
rescue Errno::ENOENT
|
|
48
|
+
terminate "Can't find configuration file #{config_file}.\n"\
|
|
49
|
+
'Please run foreplay setup or create the file manually.'
|
|
50
|
+
rescue Psych::SyntaxError
|
|
51
|
+
terminate "I don't understand the configuration file #{config_file}.\n"\
|
|
52
|
+
'Please run foreplay setup or edit the file manually.'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def config_file
|
|
56
|
+
@config_file ||= (filters['config_file'] || DEFAULT_CONFIG_FILE)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -1,48 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
46
|
-
|
|
1
|
+
module Foreplay
|
|
2
|
+
class Engine
|
|
3
|
+
class Logger
|
|
4
|
+
INDENT = 4
|
|
5
|
+
MARGIN = 24
|
|
6
|
+
|
|
7
|
+
attr_reader :message, :options
|
|
8
|
+
|
|
9
|
+
def initialize(m, o = {})
|
|
10
|
+
@message = m
|
|
11
|
+
@options = o
|
|
12
|
+
|
|
13
|
+
output
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def output
|
|
17
|
+
puts formatted_message unless silent?
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def formatted_message
|
|
21
|
+
@formatted_message ||= header + message
|
|
22
|
+
.gsub(/\A\s+/, '')
|
|
23
|
+
.gsub(/\s+\z/, '')
|
|
24
|
+
.gsub(/(\r\n|\r|\n)/, "\\1#{margin}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def header
|
|
28
|
+
@header ||= (margin_format % header_content[0, margin_width - 1]).white
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def header_content
|
|
32
|
+
@header_content ||= (options[:host] || '')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def margin
|
|
36
|
+
@margin ||= margin_format % ''
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def silent?
|
|
40
|
+
@silent ||= (options[:silent] == true) || message.blank?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def margin_width
|
|
44
|
+
@margin_width ||= MARGIN + INDENT * (options[:indent] || 0)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def margin_format
|
|
48
|
+
@margin_format ||= "%-#{margin_width}s"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
47
51
|
end
|
|
48
52
|
end
|
data/lib/foreplay/engine/port.rb
CHANGED
|
@@ -1,77 +1,82 @@
|
|
|
1
|
-
module Foreplay
|
|
2
|
-
|
|
1
|
+
module Foreplay
|
|
2
|
+
class Engine
|
|
3
|
+
module Port
|
|
4
|
+
include Foreplay
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
def host
|
|
7
|
+
return @host if @host
|
|
8
|
+
@host, _p = server.split(':') # Parse host + port
|
|
9
|
+
@host
|
|
10
|
+
end
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
def name
|
|
13
|
+
@name ||= instructions['name']
|
|
14
|
+
end
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
def current_port
|
|
17
|
+
@current_port ||= port_details['current_port']
|
|
18
|
+
end
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
def current_service
|
|
21
|
+
@current_service ||= port_details['current_service']
|
|
22
|
+
end
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
def former_port
|
|
25
|
+
@former_port ||= port_details['former_port']
|
|
26
|
+
end
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
def former_service
|
|
29
|
+
@former_service ||= port_details['former_service']
|
|
30
|
+
end
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
def current_port_file
|
|
33
|
+
@current_port_file ||= ".foreplay/#{name}/current_port"
|
|
34
|
+
end
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
def port_steps
|
|
37
|
+
@port_steps ||= [
|
|
38
|
+
{
|
|
39
|
+
'command' => "mkdir -p .foreplay/#{name} && touch #{current_port_file} && cat #{current_port_file}",
|
|
40
|
+
'silent' => true
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
end
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
def current_port_remote
|
|
46
|
+
return @current_port_remote if @current_port_remote
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
@current_port_remote = Foreplay::Engine::Remote
|
|
49
|
+
.new(server, port_steps, instructions)
|
|
50
|
+
.__send__(mode)
|
|
51
|
+
.strip
|
|
52
|
+
.to_i
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
if @current_port_remote == 0
|
|
55
|
+
message = 'No instance is currently deployed'
|
|
56
|
+
@current_port_remote = DEFAULT_PORT + PORT_GAP
|
|
57
|
+
else
|
|
58
|
+
message = "Current instance is using port #{@current_port_remote}"
|
|
59
|
+
end
|
|
57
60
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
log message, host: host
|
|
62
|
+
@current_port_remote
|
|
63
|
+
end
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
|
|
65
|
+
def port_details
|
|
66
|
+
return @port_details if @port_details
|
|
64
67
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
cp = current_port_remote
|
|
69
|
+
port = instructions['port'].to_i
|
|
70
|
+
ports = [port + PORT_GAP, port]
|
|
71
|
+
cp, fp = cp == port ? ports : ports.reverse
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
@port_details = {
|
|
74
|
+
'current_port' => cp,
|
|
75
|
+
'current_service' => "#{name}-#{cp}",
|
|
76
|
+
'former_port' => fp,
|
|
77
|
+
'former_service' => "#{name}-#{fp}"
|
|
78
|
+
}
|
|
79
|
+
end
|
|
80
|
+
end
|
|
76
81
|
end
|
|
77
82
|
end
|
|
@@ -1,42 +1,48 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
module Foreplay
|
|
2
|
+
class Engine
|
|
3
|
+
class Remote
|
|
4
|
+
class Check
|
|
5
|
+
include Foreplay
|
|
6
|
+
attr_reader :host, :steps, :instructions
|
|
7
|
+
|
|
8
|
+
def initialize(h, s, i)
|
|
9
|
+
@host = h
|
|
10
|
+
@steps = s
|
|
11
|
+
@instructions = i
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def perform
|
|
15
|
+
steps.each do |step|
|
|
16
|
+
log "#{(step['commentary'] || step['command']).yellow}", host: host, silent: step['silent']
|
|
17
|
+
|
|
18
|
+
if step.key? 'key'
|
|
19
|
+
list_file_contents step['key']
|
|
20
|
+
else
|
|
21
|
+
list_commands step
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
''
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def list_file_contents(id)
|
|
29
|
+
i = instructions[id]
|
|
30
|
+
|
|
31
|
+
if i.is_a? Hash
|
|
32
|
+
i.each { |k, v| log "#{k}: #{v}", host: host, indent: 1 }
|
|
33
|
+
else
|
|
34
|
+
log i, host: host, indent: 1
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def list_commands(step)
|
|
39
|
+
commands = Foreplay::Engine::Step.new(host, step, instructions).commands
|
|
40
|
+
|
|
41
|
+
commands.each do |command|
|
|
42
|
+
log command, host: host, silent: step['silent']
|
|
43
|
+
end
|
|
44
|
+
end
|
|
19
45
|
end
|
|
20
46
|
end
|
|
21
|
-
|
|
22
|
-
''
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def list_file_contents(id)
|
|
26
|
-
i = instructions[id]
|
|
27
|
-
|
|
28
|
-
if i.is_a? Hash
|
|
29
|
-
i.each { |k, v| log "#{k}: #{v}", host: host, indent: 1 }
|
|
30
|
-
else
|
|
31
|
-
log i, host: host, indent: 1
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def list_commands(step)
|
|
36
|
-
commands = Foreplay::Engine::Step.new(host, step, instructions).commands
|
|
37
|
-
|
|
38
|
-
commands.each do |command|
|
|
39
|
-
log command, host: host, silent: step['silent']
|
|
40
|
-
end
|
|
41
47
|
end
|
|
42
48
|
end
|
|
@@ -1,35 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
module Foreplay
|
|
2
|
+
class Engine
|
|
3
|
+
class Remote
|
|
4
|
+
class Step
|
|
5
|
+
include Foreplay
|
|
6
|
+
attr_reader :host, :shell, :step, :instructions
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
def initialize(h, sh, st, i)
|
|
9
|
+
@host = h
|
|
10
|
+
@shell = sh
|
|
11
|
+
@step = st
|
|
12
|
+
@instructions = i
|
|
13
|
+
end
|
|
11
14
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
def execute
|
|
16
|
+
s = Foreplay::Engine::Step.new(host, step, instructions)
|
|
17
|
+
s.announce
|
|
18
|
+
output s.commands.map { |command| execute_command(command) }.join
|
|
19
|
+
end
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
def execute_command(command)
|
|
22
|
+
o = ''
|
|
23
|
+
process = shell.execute command
|
|
24
|
+
process.on_output { |_, po| o += po }
|
|
25
|
+
shell.wait!
|
|
26
|
+
terminate(o) unless step['ignore_error'] == true || process.exit_status == 0
|
|
27
|
+
o
|
|
28
|
+
end
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
def silent
|
|
31
|
+
@silent ||= instructions['verbose'] ? false : step['silent']
|
|
32
|
+
end
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
def output(o)
|
|
35
|
+
log o, host: host, silent: silent, indent: 1
|
|
36
|
+
o
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
34
40
|
end
|
|
35
41
|
end
|