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
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: foreplay
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Xenapto
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-04-
|
|
11
|
+
date: 2015-04-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -24,20 +24,6 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '3.2'
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: colorize
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0.7'
|
|
34
|
-
type: :runtime
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0.7'
|
|
41
27
|
- !ruby/object:Gem::Dependency
|
|
42
28
|
name: foreman
|
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -70,134 +56,128 @@ dependencies:
|
|
|
70
56
|
name: bundler
|
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
|
72
58
|
requirements:
|
|
73
|
-
- - "
|
|
59
|
+
- - "~>"
|
|
74
60
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: '1.
|
|
61
|
+
version: '1.9'
|
|
76
62
|
type: :development
|
|
77
63
|
prerelease: false
|
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
65
|
requirements:
|
|
80
|
-
- - "
|
|
66
|
+
- - "~>"
|
|
81
67
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: '1.
|
|
68
|
+
version: '1.9'
|
|
83
69
|
- !ruby/object:Gem::Dependency
|
|
84
70
|
name: rake
|
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
|
86
72
|
requirements:
|
|
87
|
-
- - "
|
|
73
|
+
- - "~>"
|
|
88
74
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '10.
|
|
75
|
+
version: '10.4'
|
|
90
76
|
type: :development
|
|
91
77
|
prerelease: false
|
|
92
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
79
|
requirements:
|
|
94
|
-
- - "
|
|
80
|
+
- - "~>"
|
|
95
81
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '10.
|
|
82
|
+
version: '10.4'
|
|
97
83
|
- !ruby/object:Gem::Dependency
|
|
98
84
|
name: rspec
|
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
|
100
86
|
requirements:
|
|
101
|
-
- - "
|
|
87
|
+
- - "~>"
|
|
102
88
|
- !ruby/object:Gem::Version
|
|
103
89
|
version: '3.2'
|
|
104
90
|
type: :development
|
|
105
91
|
prerelease: false
|
|
106
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
93
|
requirements:
|
|
108
|
-
- - "
|
|
94
|
+
- - "~>"
|
|
109
95
|
- !ruby/object:Gem::Version
|
|
110
96
|
version: '3.2'
|
|
111
97
|
- !ruby/object:Gem::Dependency
|
|
112
98
|
name: cucumber
|
|
113
99
|
requirement: !ruby/object:Gem::Requirement
|
|
114
100
|
requirements:
|
|
115
|
-
- - "
|
|
101
|
+
- - "~>"
|
|
116
102
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: '
|
|
103
|
+
version: '2.0'
|
|
118
104
|
type: :development
|
|
119
105
|
prerelease: false
|
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
107
|
requirements:
|
|
122
|
-
- - "
|
|
108
|
+
- - "~>"
|
|
123
109
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '
|
|
110
|
+
version: '2.0'
|
|
125
111
|
- !ruby/object:Gem::Dependency
|
|
126
112
|
name: aruba
|
|
127
113
|
requirement: !ruby/object:Gem::Requirement
|
|
128
114
|
requirements:
|
|
129
|
-
- - "
|
|
115
|
+
- - "~>"
|
|
130
116
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: '0.
|
|
117
|
+
version: '0.6'
|
|
132
118
|
type: :development
|
|
133
119
|
prerelease: false
|
|
134
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
121
|
requirements:
|
|
136
|
-
- - "
|
|
122
|
+
- - "~>"
|
|
137
123
|
- !ruby/object:Gem::Version
|
|
138
|
-
version: '0.
|
|
124
|
+
version: '0.6'
|
|
139
125
|
- !ruby/object:Gem::Dependency
|
|
140
126
|
name: gem-release
|
|
141
127
|
requirement: !ruby/object:Gem::Requirement
|
|
142
128
|
requirements:
|
|
143
|
-
- - "
|
|
129
|
+
- - "~>"
|
|
144
130
|
- !ruby/object:Gem::Version
|
|
145
131
|
version: '0.7'
|
|
146
132
|
type: :development
|
|
147
133
|
prerelease: false
|
|
148
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
135
|
requirements:
|
|
150
|
-
- - "
|
|
136
|
+
- - "~>"
|
|
151
137
|
- !ruby/object:Gem::Version
|
|
152
138
|
version: '0.7'
|
|
153
139
|
- !ruby/object:Gem::Dependency
|
|
154
140
|
name: simplecov
|
|
155
141
|
requirement: !ruby/object:Gem::Requirement
|
|
156
142
|
requirements:
|
|
157
|
-
- - "
|
|
158
|
-
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0.7'
|
|
160
|
-
- - ">="
|
|
143
|
+
- - "~>"
|
|
161
144
|
- !ruby/object:Gem::Version
|
|
162
|
-
version: 0.
|
|
145
|
+
version: '0.10'
|
|
163
146
|
type: :development
|
|
164
147
|
prerelease: false
|
|
165
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
166
149
|
requirements:
|
|
167
|
-
- - "
|
|
168
|
-
- !ruby/object:Gem::Version
|
|
169
|
-
version: '0.7'
|
|
170
|
-
- - ">="
|
|
150
|
+
- - "~>"
|
|
171
151
|
- !ruby/object:Gem::Version
|
|
172
|
-
version: 0.
|
|
152
|
+
version: '0.10'
|
|
173
153
|
- !ruby/object:Gem::Dependency
|
|
174
154
|
name: coveralls
|
|
175
155
|
requirement: !ruby/object:Gem::Requirement
|
|
176
156
|
requirements:
|
|
177
|
-
- - "
|
|
157
|
+
- - "~>"
|
|
178
158
|
- !ruby/object:Gem::Version
|
|
179
|
-
version: '0.
|
|
159
|
+
version: '0.8'
|
|
180
160
|
type: :development
|
|
181
161
|
prerelease: false
|
|
182
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
183
163
|
requirements:
|
|
184
|
-
- - "
|
|
164
|
+
- - "~>"
|
|
185
165
|
- !ruby/object:Gem::Version
|
|
186
|
-
version: '0.
|
|
166
|
+
version: '0.8'
|
|
187
167
|
- !ruby/object:Gem::Dependency
|
|
188
168
|
name: rubocop
|
|
189
169
|
requirement: !ruby/object:Gem::Requirement
|
|
190
170
|
requirements:
|
|
191
|
-
- - "
|
|
171
|
+
- - "~>"
|
|
192
172
|
- !ruby/object:Gem::Version
|
|
193
|
-
version: '0.
|
|
173
|
+
version: '0.30'
|
|
194
174
|
type: :development
|
|
195
175
|
prerelease: false
|
|
196
176
|
version_requirements: !ruby/object:Gem::Requirement
|
|
197
177
|
requirements:
|
|
198
|
-
- - "
|
|
178
|
+
- - "~>"
|
|
199
179
|
- !ruby/object:Gem::Version
|
|
200
|
-
version: '0.
|
|
180
|
+
version: '0.30'
|
|
201
181
|
description: Deploying Rails projects to Ubuntu using Foreman
|
|
202
182
|
email:
|
|
203
183
|
- developers@xenapto.com
|
|
@@ -223,14 +203,21 @@ files:
|
|
|
223
203
|
- foreplay.rake
|
|
224
204
|
- lib/foreplay.rb
|
|
225
205
|
- lib/foreplay/cli.rb
|
|
226
|
-
- lib/foreplay/
|
|
206
|
+
- lib/foreplay/engine.rb
|
|
207
|
+
- lib/foreplay/engine/remote.rb
|
|
208
|
+
- lib/foreplay/engine/role.rb
|
|
209
|
+
- lib/foreplay/engine/server.rb
|
|
210
|
+
- lib/foreplay/engine/step.rb
|
|
211
|
+
- lib/foreplay/engine/steps.yml
|
|
212
|
+
- lib/foreplay/foreplay.rb
|
|
213
|
+
- lib/foreplay/launcher.rb
|
|
227
214
|
- lib/foreplay/setup.rb
|
|
228
215
|
- lib/foreplay/setup/foreplay.yml
|
|
229
|
-
- lib/foreplay/utility.rb
|
|
230
216
|
- lib/foreplay/version.rb
|
|
217
|
+
- lib/string.rb
|
|
231
218
|
- spec/lib/foreplay/deploy_spec.rb
|
|
219
|
+
- spec/lib/foreplay/engine_spec.rb
|
|
232
220
|
- spec/lib/foreplay/setup_spec.rb
|
|
233
|
-
- spec/lib/foreplay/utility_spec.rb
|
|
234
221
|
- spec/spec_helper.rb
|
|
235
222
|
homepage: https://github.com/Xenapto/foreplay
|
|
236
223
|
licenses:
|
|
@@ -252,16 +239,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
252
239
|
version: '0'
|
|
253
240
|
requirements: []
|
|
254
241
|
rubyforge_project:
|
|
255
|
-
rubygems_version: 2.4.
|
|
242
|
+
rubygems_version: 2.4.6
|
|
256
243
|
signing_key:
|
|
257
244
|
specification_version: 4
|
|
258
|
-
summary: 'Example: foreplay
|
|
245
|
+
summary: 'Example: foreplay deploy production'
|
|
259
246
|
test_files:
|
|
260
247
|
- features/check.feature
|
|
261
248
|
- features/deploy.feature
|
|
262
249
|
- features/setup.feature
|
|
263
250
|
- features/support/env.rb
|
|
264
251
|
- spec/lib/foreplay/deploy_spec.rb
|
|
252
|
+
- spec/lib/foreplay/engine_spec.rb
|
|
265
253
|
- spec/lib/foreplay/setup_spec.rb
|
|
266
|
-
- spec/lib/foreplay/utility_spec.rb
|
|
267
254
|
- spec/spec_helper.rb
|
data/lib/foreplay/deploy.rb
DELETED
|
@@ -1,395 +0,0 @@
|
|
|
1
|
-
require 'thor/group'
|
|
2
|
-
require 'yaml'
|
|
3
|
-
require 'net/ssh'
|
|
4
|
-
require 'net/ssh/shell'
|
|
5
|
-
require 'active_support/inflector'
|
|
6
|
-
require 'active_support/core_ext/object'
|
|
7
|
-
require 'active_support/core_ext/hash'
|
|
8
|
-
require 'colorize'
|
|
9
|
-
require 'foreplay/utility'
|
|
10
|
-
|
|
11
|
-
module Foreplay
|
|
12
|
-
class Deploy < Thor::Group
|
|
13
|
-
include Thor::Actions
|
|
14
|
-
|
|
15
|
-
argument :mode, type: :string, required: true
|
|
16
|
-
argument :environment, type: :string, required: true
|
|
17
|
-
argument :filters, type: :hash, required: false
|
|
18
|
-
|
|
19
|
-
DEFAULTS_KEY = 'defaults'
|
|
20
|
-
INDENT = "\t"
|
|
21
|
-
|
|
22
|
-
def parse
|
|
23
|
-
# Explain what we're going to do
|
|
24
|
-
message = "#{mode.capitalize}ing #{environment.dup.yellow} environment, "
|
|
25
|
-
message += "#{explanatory_text(filters, 'role')}, #{explanatory_text(filters, 'server')}"
|
|
26
|
-
puts message
|
|
27
|
-
|
|
28
|
-
config_file = "#{Dir.getwd}/config/foreplay.yml"
|
|
29
|
-
|
|
30
|
-
begin
|
|
31
|
-
config_yml = File.read config_file
|
|
32
|
-
rescue Errno::ENOENT
|
|
33
|
-
terminate "Can't find configuration file #{config_file}.\nPlease run foreplay setup or create the file manually."
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
config_all = YAML.load(config_yml)
|
|
37
|
-
config_env = config_all[environment] || {}
|
|
38
|
-
|
|
39
|
-
# This environment
|
|
40
|
-
unless config_all.key? environment
|
|
41
|
-
terminate("No deployment configuration defined for #{environment} environment.\nCheck #{config_file}")
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Servers asked for
|
|
45
|
-
server_filter = filters['server'].split(',') if filters.key?('server')
|
|
46
|
-
|
|
47
|
-
# Establish defaults
|
|
48
|
-
# First the default defaults
|
|
49
|
-
defaults = {
|
|
50
|
-
name: File.basename(Dir.getwd),
|
|
51
|
-
environment: environment,
|
|
52
|
-
env: { 'RAILS_ENV' => environment },
|
|
53
|
-
port: 50_000
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
defaults = Foreplay::Utility.supermerge(defaults, config_all[DEFAULTS_KEY]) if config_all.key? DEFAULTS_KEY
|
|
57
|
-
defaults = Foreplay::Utility.supermerge(defaults, config_env[DEFAULTS_KEY]) if config_env.key? DEFAULTS_KEY
|
|
58
|
-
threads = []
|
|
59
|
-
|
|
60
|
-
config_env.each do |role, additional_instructions|
|
|
61
|
-
next if role == DEFAULTS_KEY # 'defaults' is not a role
|
|
62
|
-
# Only deploy to the role we've specified (or all roles if none is specified)
|
|
63
|
-
next if filters.key?('role') && filters['role'] != role
|
|
64
|
-
|
|
65
|
-
instructions = Foreplay::Utility.supermerge(defaults, additional_instructions).symbolize_keys
|
|
66
|
-
instructions[:role] = role
|
|
67
|
-
required_keys = [:name, :environment, :role, :servers, :path, :repository]
|
|
68
|
-
|
|
69
|
-
required_keys.each do |key|
|
|
70
|
-
next if instructions.key? key
|
|
71
|
-
terminate("Required key #{key} not found in instructions for #{environment} environment.\nCheck #{config_file}")
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# Apply server filter
|
|
75
|
-
instructions[:servers] &= server_filter if server_filter
|
|
76
|
-
|
|
77
|
-
threads.concat deploy_role(instructions)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
threads.each(&:join)
|
|
81
|
-
|
|
82
|
-
puts mode == :deploy ? 'Finished deployment' : 'Deployment configuration check was successful'
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
private
|
|
86
|
-
|
|
87
|
-
def deploy_role(instructions)
|
|
88
|
-
servers = instructions[:servers]
|
|
89
|
-
threads = []
|
|
90
|
-
preposition = mode == :deploy ? 'to' : 'for'
|
|
91
|
-
|
|
92
|
-
if servers.length > 1
|
|
93
|
-
message = "#{mode.capitalize}ing #{instructions[:name].yellow} #{preposition} #{servers.join(', ').yellow} for the "
|
|
94
|
-
message += "#{instructions[:role].dup.yellow} role in the #{environment.dup.yellow} environment..."
|
|
95
|
-
puts message
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
servers.each { |server| threads << Thread.new { deploy_to_server server, instructions } }
|
|
99
|
-
threads
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def deploy_to_server(server_port, instructions)
|
|
103
|
-
server, _ = server_port.split(':') # Parse server + port
|
|
104
|
-
name = instructions[:name]
|
|
105
|
-
role = instructions[:role]
|
|
106
|
-
path = instructions[:path]
|
|
107
|
-
repository = instructions[:repository]
|
|
108
|
-
branch = instructions[:branch] || 'master'
|
|
109
|
-
user = instructions[:user]
|
|
110
|
-
port = instructions[:port]
|
|
111
|
-
preposition = mode == :deploy ? 'to' : 'for'
|
|
112
|
-
|
|
113
|
-
message = "#{mode.capitalize}ing #{name.yellow} #{preposition} #{server.yellow} "
|
|
114
|
-
message += "for the #{role.dup.yellow} role in the #{environment.dup.yellow} environment"
|
|
115
|
-
puts message
|
|
116
|
-
|
|
117
|
-
# Substitute variables in the path
|
|
118
|
-
path.gsub! '%u', user
|
|
119
|
-
path.gsub! '%a', name
|
|
120
|
-
|
|
121
|
-
# Find out which port we're currently running on
|
|
122
|
-
current_port_file = ".foreplay/#{name}/current_port"
|
|
123
|
-
steps = [{ command: "mkdir -p .foreplay/#{name} && touch #{current_port_file} && cat #{current_port_file}", silent: true }]
|
|
124
|
-
|
|
125
|
-
current_port_string = execute_on_server(server_port, steps, instructions).strip!
|
|
126
|
-
|
|
127
|
-
if current_port_string.blank?
|
|
128
|
-
puts "#{server}#{INDENT}No instance is currently deployed"
|
|
129
|
-
else
|
|
130
|
-
"#{server}#{INDENT}Current instance is using port #{current_port_string}"
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
current_port = current_port_string.to_i
|
|
134
|
-
|
|
135
|
-
# Switch ports
|
|
136
|
-
if current_port == port
|
|
137
|
-
current_port = port + 1000
|
|
138
|
-
former_port = port
|
|
139
|
-
else
|
|
140
|
-
current_port = port
|
|
141
|
-
former_port = port + 1000
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# Contents of .foreman file
|
|
145
|
-
current_service = "#{name}-#{current_port}"
|
|
146
|
-
former_service = "#{name}-#{former_port}"
|
|
147
|
-
|
|
148
|
-
instructions[:foreman]['app'] = current_service
|
|
149
|
-
instructions[:foreman]['port'] = current_port
|
|
150
|
-
instructions[:foreman]['user'] = user
|
|
151
|
-
instructions[:foreman]['log'] = "$HOME/#{path}/#{current_port}/log"
|
|
152
|
-
|
|
153
|
-
# Contents of .env file
|
|
154
|
-
instructions[:env]['HOME'] = '$HOME'
|
|
155
|
-
instructions[:env]['SHELL'] = '$SHELL'
|
|
156
|
-
instructions[:env]['PATH'] = '$PATH:`which bundle`'
|
|
157
|
-
|
|
158
|
-
# Commands to execute on remote server
|
|
159
|
-
steps = [
|
|
160
|
-
{ command: "echo Foreplay version #{VERSION}",
|
|
161
|
-
commentary: "Foreplay running from #{`hostname -f`}#{`which foreman`}" },
|
|
162
|
-
{ command: "mkdir -p #{path} && cd #{path} && rm -rf #{current_port} "\
|
|
163
|
-
"&& git clone -b #{branch} #{repository} #{current_port}",
|
|
164
|
-
commentary: "Cloning #{branch} branch of repository #{repository}" },
|
|
165
|
-
{ command: "rvm rvmrc trust #{current_port}",
|
|
166
|
-
commentary: 'Trusting the .rvmrc file for the new instance' },
|
|
167
|
-
{ command: "rvm rvmrc warning ignore #{current_port}",
|
|
168
|
-
commentary: 'Ignoring the .rvmrc warning for the new instance' },
|
|
169
|
-
{ command: 'gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys D39DC0E3',
|
|
170
|
-
commentary: "Trusting RVM's public key",
|
|
171
|
-
ignore_error: true },
|
|
172
|
-
{ command: "cd #{current_port} && mkdir -p tmp doc log config",
|
|
173
|
-
commentary: 'If you have a .rvmrc file there may be a delay now while we install a new ruby' },
|
|
174
|
-
{ command: 'if [ -f .ruby-version ] ; then rvm install `cat .ruby-version` ; '\
|
|
175
|
-
'else echo "No .ruby-version file found" ; fi',
|
|
176
|
-
commentary: 'If you have a .ruby-version file there may be a delay now while we install a new ruby' },
|
|
177
|
-
{ key: :env,
|
|
178
|
-
delimiter: '=',
|
|
179
|
-
prefix: '.',
|
|
180
|
-
commentary: 'Building .env' },
|
|
181
|
-
{ key: :foreman,
|
|
182
|
-
delimiter: ': ',
|
|
183
|
-
prefix: '.',
|
|
184
|
-
commentary: 'Building .foreman' },
|
|
185
|
-
{ key: :database,
|
|
186
|
-
delimiter: ': ',
|
|
187
|
-
suffix: '.yml',
|
|
188
|
-
commentary: 'Building config/database.yml',
|
|
189
|
-
before: ' ',
|
|
190
|
-
header: "#{environment}:",
|
|
191
|
-
path: 'config/' },
|
|
192
|
-
{ key: :resque,
|
|
193
|
-
delimiter: ': ',
|
|
194
|
-
suffix: '.yml',
|
|
195
|
-
commentary: 'Building config/resque.yml',
|
|
196
|
-
before: environment,
|
|
197
|
-
path: 'config/' },
|
|
198
|
-
{ command: 'if [ -d ../cache/vendor/bundle/bundle ] ; then rm -rf ../cache/vendor/bundle/bundle'\
|
|
199
|
-
' ; else echo No evidence of legacy copy bug ; fi',
|
|
200
|
-
commentary: 'Fixing legacy copy bug' },
|
|
201
|
-
{ command: 'if [ -d ../cache/vendor/bundle ] ; then rsync -aW --no-compress --delete --info=STATS3'\
|
|
202
|
-
' ../cache/vendor/bundle/ vendor/bundle ; else echo No bundle to restore ; fi',
|
|
203
|
-
commentary: 'Attempting to restore bundle from cache' },
|
|
204
|
-
{ command: 'sudo ln -f `which bundle` /usr/bin/bundle || echo Using default version of bundle',
|
|
205
|
-
commentary: 'Setting the current version of bundle to be the default' },
|
|
206
|
-
{ command: 'bundle install --deployment --clean --jobs 2 --without development test',
|
|
207
|
-
commentary: 'Using bundler to install the required gems in deployment mode' },
|
|
208
|
-
{ command: 'mkdir -p ../cache/vendor && rsync -aW --no-compress --delete --info=STATS1'\
|
|
209
|
-
' vendor/bundle/ ../cache/vendor/bundle',
|
|
210
|
-
commentary: 'Caching bundle' },
|
|
211
|
-
{ command: 'if [ -f public/assets/manifest.yml ] ; then echo "Not precompiling assets"'\
|
|
212
|
-
" ; else RAILS_ENV=#{environment} bundle exec foreman run rake assets:precompile ; fi",
|
|
213
|
-
commentary: 'Precompiling assets unless they were supplied' },
|
|
214
|
-
{ command: 'sudo bundle exec foreman export upstart /etc/init',
|
|
215
|
-
commentary: "Converting #{current_service} to an upstart service" },
|
|
216
|
-
{ command: "sudo start #{current_service} || sudo restart #{current_service}",
|
|
217
|
-
commentary: 'Starting the service',
|
|
218
|
-
ignore_error: true },
|
|
219
|
-
{ command: "echo #{current_port} > $HOME/#{current_port_file}",
|
|
220
|
-
commentary: "Setting the port for the new instance to #{current_port}" },
|
|
221
|
-
{ command: 'sleep 60',
|
|
222
|
-
commentary: 'Waiting 60s to give service time to start' },
|
|
223
|
-
{ command: "sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{current_port}",
|
|
224
|
-
commentary: "Adding firewall rule to direct incoming traffic on port 80 to port #{current_port}" },
|
|
225
|
-
{ command: "sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{former_port}",
|
|
226
|
-
commentary: "Removing previous firewall rule directing traffic to port #{former_port}",
|
|
227
|
-
ignore_error: true },
|
|
228
|
-
{ command: 'sudo iptables-save > /etc/iptables/rules.v4',
|
|
229
|
-
commentary: 'Attempting to save firewall rules to /etc/iptables/rules.v4',
|
|
230
|
-
ignore_error: true },
|
|
231
|
-
{ command: 'sudo iptables-save > /etc/iptables.up.rules',
|
|
232
|
-
commentary: 'Attempting to save firewall rules to /etc/iptables.up.rules',
|
|
233
|
-
ignore_error: true },
|
|
234
|
-
{ command: 'sudo iptables-save -c | egrep REDIRECT --color=never',
|
|
235
|
-
ignore_error: true,
|
|
236
|
-
commentary: 'Current firewall NAT configuration:' },
|
|
237
|
-
{ command: "sudo stop #{former_service} || echo 'No previous instance running'",
|
|
238
|
-
commentary: 'Stopping the previous instance',
|
|
239
|
-
ignore_error: true }
|
|
240
|
-
]
|
|
241
|
-
|
|
242
|
-
execute_on_server server_port, steps, instructions
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
def execute_on_server(server_port, steps, instructions)
|
|
246
|
-
user = instructions[:user]
|
|
247
|
-
password = instructions[:password]
|
|
248
|
-
keyfile = instructions[:keyfile]
|
|
249
|
-
private_key = instructions[:private_key]
|
|
250
|
-
|
|
251
|
-
keyfile.sub! '~', ENV['HOME'] || '/' unless keyfile.blank? # Remote shell won't expand this for us
|
|
252
|
-
|
|
253
|
-
server, port = server_port.split(':') # Parse server + port
|
|
254
|
-
port ||= 22
|
|
255
|
-
|
|
256
|
-
# SSH authentication methods
|
|
257
|
-
options = { verbose: :warn, port: port }
|
|
258
|
-
|
|
259
|
-
if password.blank?
|
|
260
|
-
# If there's no password we must supply a private key
|
|
261
|
-
if private_key.blank?
|
|
262
|
-
message = 'No authentication methods supplied. You must supply a private key, key file or password in the configuration file'
|
|
263
|
-
terminate(message) if keyfile.blank?
|
|
264
|
-
# Get the key from the key file
|
|
265
|
-
puts "#{INDENT}Using private key from #{keyfile}"
|
|
266
|
-
private_key = File.read keyfile
|
|
267
|
-
else
|
|
268
|
-
puts "#{INDENT}Using private key from the configuration file"
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
options[:key_data] = [private_key]
|
|
272
|
-
else
|
|
273
|
-
# Use the password supplied
|
|
274
|
-
options[:password] = password
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# Capture output of last command to return to the calling routine
|
|
278
|
-
output = ''
|
|
279
|
-
|
|
280
|
-
if mode == :deploy
|
|
281
|
-
puts "#{server}#{INDENT}Connecting to #{server} on port #{port}"
|
|
282
|
-
|
|
283
|
-
# SSH connection
|
|
284
|
-
session = start_session(server, server_port, user, options)
|
|
285
|
-
|
|
286
|
-
puts "#{server}#{INDENT}Successfully connected to #{server} on port #{port}"
|
|
287
|
-
|
|
288
|
-
session.shell do |sh|
|
|
289
|
-
steps.each do |step|
|
|
290
|
-
# Output from this step
|
|
291
|
-
output = ''
|
|
292
|
-
previous = '' # We don't need or want the final CRLF
|
|
293
|
-
commands = build_step server, step, instructions
|
|
294
|
-
|
|
295
|
-
commands.each do |command|
|
|
296
|
-
process = sh.execute command
|
|
297
|
-
|
|
298
|
-
process.on_output do |_, o|
|
|
299
|
-
previous = o
|
|
300
|
-
output += previous
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
sh.wait!
|
|
304
|
-
|
|
305
|
-
if step[:ignore_error] == true || process.exit_status == 0
|
|
306
|
-
print output.gsub!(/^/, "#{server}#{INDENT * 2}") unless step[:silent] == true || output.blank?
|
|
307
|
-
else
|
|
308
|
-
terminate(output)
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
session.close
|
|
315
|
-
else
|
|
316
|
-
# Deployment check: just say what we would have done
|
|
317
|
-
puts "#{server}#{INDENT * 2}Connection options:"
|
|
318
|
-
options.each { |k, v| puts "#{server}#{INDENT * 2}#{k}: #{v}" }
|
|
319
|
-
|
|
320
|
-
puts "#{server}#{INDENT * 2}"
|
|
321
|
-
puts "#{server}#{INDENT * 2}Deployment instructions:"
|
|
322
|
-
steps.each do |step|
|
|
323
|
-
commands = build_step server, step, instructions
|
|
324
|
-
commands.each { |command| puts "#{server}#{INDENT * 2}#{command}" unless step[:silent] }
|
|
325
|
-
end
|
|
326
|
-
end
|
|
327
|
-
|
|
328
|
-
output
|
|
329
|
-
end
|
|
330
|
-
|
|
331
|
-
def start_session(server, server_port, user, options)
|
|
332
|
-
Net::SSH.start(server, user, options)
|
|
333
|
-
rescue SocketError => e
|
|
334
|
-
terminate "#{server}#{INDENT}There was a problem starting an ssh session on #{server_port}:\n#{e.message}"
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
def build_step(server, step, instructions)
|
|
338
|
-
puts "#{server}#{INDENT}#{(step[:commentary] || step[:command]).yellow}" unless step[:silent] == true
|
|
339
|
-
|
|
340
|
-
# Each step can be (1) a command or (2) a series of values to add to a file
|
|
341
|
-
if step.key?(:key)
|
|
342
|
-
if instructions.key?(step[:key])
|
|
343
|
-
build_commands step, instructions
|
|
344
|
-
else
|
|
345
|
-
[]
|
|
346
|
-
end
|
|
347
|
-
else
|
|
348
|
-
# ...or just execute the command specified
|
|
349
|
-
[step[:command]]
|
|
350
|
-
end
|
|
351
|
-
end
|
|
352
|
-
|
|
353
|
-
def build_commands(step, instructions)
|
|
354
|
-
# Add values from the config file to a file on the remote machine
|
|
355
|
-
key = step[:key]
|
|
356
|
-
prefix = step[:prefix] || ''
|
|
357
|
-
suffix = step[:suffix] || ''
|
|
358
|
-
path = step[:path] || ''
|
|
359
|
-
before = step[:before] || ''
|
|
360
|
-
delimiter = step[:delimiter] || ''
|
|
361
|
-
after = step[:after] || ''
|
|
362
|
-
|
|
363
|
-
step[:silent] = true
|
|
364
|
-
filename = "#{path}#{prefix}#{key}#{suffix}"
|
|
365
|
-
|
|
366
|
-
if step.key?(:header)
|
|
367
|
-
commands = ["echo \"#{step[:header]}\" > #{filename}"]
|
|
368
|
-
redirect = '>>'
|
|
369
|
-
else
|
|
370
|
-
commands = []
|
|
371
|
-
redirect = '>'
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
if instructions[key].is_a? Hash
|
|
375
|
-
instructions[key].each do |k, v|
|
|
376
|
-
commands << "echo \"#{before}#{k}#{delimiter}#{v}#{after}\" #{redirect} #{filename}"
|
|
377
|
-
redirect = '>>'
|
|
378
|
-
end
|
|
379
|
-
else
|
|
380
|
-
commands << "echo \"#{before}#{delimiter}#{instructions[key]}#{after}\" #{redirect} #{filename}"
|
|
381
|
-
redirect = '>>'
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
commands
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
def explanatory_text(hsh, key)
|
|
388
|
-
hsh.key?(key) ? "#{hsh[key].dup.yellow} #{key}" : "all #{key.pluralize}"
|
|
389
|
-
end
|
|
390
|
-
|
|
391
|
-
def terminate(message)
|
|
392
|
-
fail message
|
|
393
|
-
end
|
|
394
|
-
end
|
|
395
|
-
end
|
data/lib/foreplay/utility.rb
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
module Foreplay
|
|
2
|
-
class Utility
|
|
3
|
-
# Returns a new hash with +hash+ and +other_hash+ merged recursively, including arrays.
|
|
4
|
-
#
|
|
5
|
-
# h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
|
|
6
|
-
# h2 = { x: { y: [7,8,9] }, z: 'xyz' }
|
|
7
|
-
# h1.supermerge(h2)
|
|
8
|
-
# #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
|
|
9
|
-
def self.supermerge(hash, other_hash)
|
|
10
|
-
fail 'supermerge only works if you pass two hashes. '\
|
|
11
|
-
"You passed a #{hash.class} and a #{other_hash.class}." unless hash.is_a?(Hash) && other_hash.is_a?(Hash)
|
|
12
|
-
|
|
13
|
-
new_hash = hash.deep_dup.with_indifferent_access
|
|
14
|
-
|
|
15
|
-
other_hash.each_pair do |k, v|
|
|
16
|
-
tv = new_hash[k]
|
|
17
|
-
|
|
18
|
-
if tv.is_a?(Hash) && v.is_a?(Hash)
|
|
19
|
-
new_hash[k] = Foreplay::Utility.supermerge(tv, v)
|
|
20
|
-
elsif tv.is_a?(Array) || v.is_a?(Array)
|
|
21
|
-
new_hash[k] = Array.wrap(tv) + Array.wrap(v)
|
|
22
|
-
else
|
|
23
|
-
new_hash[k] = v
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
new_hash
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|