foreplay 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -5
- data/features/deploy.feature +1 -1
- data/lib/foreplay/deploy.rb +29 -23
- data/lib/foreplay/version.rb +1 -1
- data/spec/lib/foreplay/deploy_spec.rb +6 -46
- metadata +4 -5
- data/foreplay.rb +0 -246
data/README.md
CHANGED
@@ -103,8 +103,12 @@ end
|
|
103
103
|
|
104
104
|
## Contributing
|
105
105
|
|
106
|
-
1.
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
106
|
+
1. Fork it
|
107
|
+
1. Create your feature branch (`git checkout -b my-new-feature`)
|
108
|
+
1. Commit your changes (`git commit -am 'Add some feature'`)
|
109
|
+
1. Push to the branch (`git push origin my-new-feature`)
|
110
|
+
1. Create new Pull Request
|
111
|
+
|
112
|
+
## Acknowledgements
|
113
|
+
|
114
|
+
1. Thanks to Ryan Bigg for the guide to making your first gem https://github.com/radar/guides/blob/master/gem-development.md
|
data/features/deploy.feature
CHANGED
@@ -91,6 +91,6 @@ Feature: deploy
|
|
91
91
|
Scenario: deploy
|
92
92
|
When I run `foreplay setup -r git@github.com:Xenapto/foreplay.git -s web.example.com --password "top-secret"`
|
93
93
|
And I run `foreplay deploy production`
|
94
|
-
Then the output should contain "Deploying aruba to web.example.com
|
94
|
+
Then the output should contain "Deploying aruba to web.example.com for the web role in the production environment"
|
95
95
|
And the output should contain "Connecting to web.example.com"
|
96
96
|
And the output should contain "There was a problem starting an ssh session on web.example.com"
|
data/lib/foreplay/deploy.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'thor/group'
|
2
2
|
require 'yaml'
|
3
3
|
require 'net/ssh'
|
4
|
+
require 'net/ssh/shell'
|
4
5
|
require 'active_support/inflector'
|
5
6
|
require 'active_support/core_ext/object'
|
6
7
|
require 'active_support/core_ext/hash'
|
@@ -15,7 +16,8 @@ module Foreplay
|
|
15
16
|
argument :environment, :type => :string, :required => true
|
16
17
|
argument :filters, :type => :hash, :required => false
|
17
18
|
|
18
|
-
DEFAULTS_KEY
|
19
|
+
DEFAULTS_KEY = 'defaults'
|
20
|
+
INDENT = ' ' * 4
|
19
21
|
|
20
22
|
def parse
|
21
23
|
# Explain what we're going to do
|
@@ -73,7 +75,7 @@ module Foreplay
|
|
73
75
|
servers = instructions[:servers]
|
74
76
|
preposition = mode == :deploy ? 'to' : 'for'
|
75
77
|
|
76
|
-
puts "#{mode.capitalize}ing #{instructions[:name].yellow} #{preposition} #{servers.join(', ').yellow}
|
78
|
+
puts "#{mode.capitalize}ing #{instructions[:name].yellow} #{preposition} #{servers.join(', ').yellow} for the #{instructions[:role].dup.yellow} role in the #{environment.dup.yellow} environment..." if servers.length > 1
|
77
79
|
servers.each { |server| deploy_to_server server, instructions }
|
78
80
|
end
|
79
81
|
|
@@ -88,7 +90,7 @@ module Foreplay
|
|
88
90
|
|
89
91
|
instructions[:server] = server
|
90
92
|
|
91
|
-
puts "#{mode.capitalize}ing #{name.yellow} #{preposition} #{server.yellow}
|
93
|
+
puts "#{mode.capitalize}ing #{name.yellow} #{preposition} #{server.yellow} for the #{role.dup.yellow} role in the #{environment.dup.yellow} environment"
|
92
94
|
|
93
95
|
# Substitute variables in the path
|
94
96
|
path.gsub! '%u', user
|
@@ -98,7 +100,7 @@ module Foreplay
|
|
98
100
|
steps = [ { :command => 'mkdir -p .foreplay && touch .foreplay/current_port && cat .foreplay/current_port', :silent => true } ]
|
99
101
|
|
100
102
|
current_port_string = execute_on_server(steps, instructions).strip!
|
101
|
-
puts current_port_string.blank? ?
|
103
|
+
puts current_port_string.blank? ? "#{INDENT}No instance is currently deployed" : "#{INDENT}Current instance is using port #{current_port_string}"
|
102
104
|
|
103
105
|
current_port = current_port_string.to_i
|
104
106
|
|
@@ -129,6 +131,8 @@ module Foreplay
|
|
129
131
|
:commentary => 'Trusting the .rvmrc file for the new instance' },
|
130
132
|
{ :command => "cd #{current_port}",
|
131
133
|
:commentary => 'Configuring the new instance' },
|
134
|
+
{ :command => 'mkdir -p config',
|
135
|
+
:commentary => "Making sure the config directory exists" },
|
132
136
|
{ :key => :env,
|
133
137
|
:delimiter => '=',
|
134
138
|
:prefix => '.',
|
@@ -144,29 +148,31 @@ module Foreplay
|
|
144
148
|
:before => ' ',
|
145
149
|
:header => "#{environment}:",
|
146
150
|
:path => 'config/' },
|
147
|
-
{ :command =>
|
151
|
+
{ :command => 'bundle install',
|
148
152
|
:commentary => 'Using bundler to install the required gems' },
|
149
|
-
{ :command =>
|
153
|
+
{ :command => 'sudo ln -f `which foreman` /usr/bin/foreman',
|
150
154
|
:commentary => 'Setting the current version of foreman to be the default' },
|
151
|
-
{ :command =>
|
155
|
+
{ :command => 'sudo foreman export upstart /etc/init',
|
152
156
|
:commentary => "Converting #{current_service} to an upstart service" },
|
153
157
|
{ :command => "sudo start #{current_service} || sudo restart #{current_service}",
|
154
158
|
:commentary => 'Starting the service',
|
155
159
|
:ignore_error => true },
|
156
160
|
{ :command => 'sleep 60',
|
157
161
|
:commentary => 'Waiting 60s to give service time to start' },
|
158
|
-
{ :command => "sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{current_port
|
162
|
+
{ :command => "sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{current_port}",
|
159
163
|
:commentary => "Adding firewall rule to direct incoming traffic on port 80 to port #{current_port}" },
|
160
|
-
{ :command => "sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{former_port
|
161
|
-
:commentary => "Removing previous firewall directing traffic to port #{former_port}",
|
164
|
+
{ :command => "sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{former_port}",
|
165
|
+
:commentary => "Removing previous firewall rule directing traffic to port #{former_port}",
|
162
166
|
:ignore_error => true },
|
163
|
-
{ :command =>
|
164
|
-
:commentary =>
|
165
|
-
|
166
|
-
|
167
|
-
|
167
|
+
{ :command => 'sudo iptables-save > /etc/iptables/rules.v4',
|
168
|
+
:commentary => 'Attempting to save firewall rules to /etc/iptables/rules.v4',
|
169
|
+
:ignore_error => true },
|
170
|
+
{ :command => 'sudo iptables-save > /etc/iptables.up.rules',
|
171
|
+
:commentary => 'Attempting to save firewall rules to /etc/iptables.up.rules',
|
172
|
+
:ignore_error => true },
|
173
|
+
{ :command => 'sudo iptables-save -c | egrep REDIRECT --color=never',
|
168
174
|
:ignore_error => true,
|
169
|
-
:commentary =>
|
175
|
+
:commentary => 'Current firewall NAT configuration:' },
|
170
176
|
{ :command => "sudo stop #{former_service} || echo 'No previous instance running'",
|
171
177
|
:commentary => 'Stopping the previous instance',
|
172
178
|
:ignore_error => true },
|
@@ -192,10 +198,10 @@ module Foreplay
|
|
192
198
|
if private_key.blank?
|
193
199
|
terminate('No authentication methods supplied. You must supply a private key, key file or password in the configuration file') if keyfile.blank?
|
194
200
|
# Get the key from the key file
|
195
|
-
puts "
|
201
|
+
puts "#{INDENT}Using private key from #{keyfile}"
|
196
202
|
private_key = File.read keyfile
|
197
203
|
else
|
198
|
-
puts "
|
204
|
+
puts "#{INDENT}Using private key from the configuration file"
|
199
205
|
end
|
200
206
|
|
201
207
|
options[:key_data] = [private_key]
|
@@ -208,12 +214,12 @@ module Foreplay
|
|
208
214
|
output = ''
|
209
215
|
|
210
216
|
if mode == :deploy
|
211
|
-
puts "
|
217
|
+
puts "#{INDENT}Connecting to #{server}"
|
212
218
|
|
213
219
|
# SSH connection
|
214
220
|
begin
|
215
221
|
Net::SSH.start(server, user, options) do |session|
|
216
|
-
puts "
|
222
|
+
puts "#{INDENT}Successfully connected to #{server}"
|
217
223
|
|
218
224
|
session.shell do |sh|
|
219
225
|
steps.each do |step|
|
@@ -234,7 +240,7 @@ module Foreplay
|
|
234
240
|
sh.wait!
|
235
241
|
|
236
242
|
if step[:ignore_error] == true || process.exit_status == 0
|
237
|
-
print output.gsub!(/^/,
|
243
|
+
print output.gsub!(/^/, INDENT * 2) unless step[:silent] == true || output.blank?
|
238
244
|
else
|
239
245
|
terminate(output)
|
240
246
|
end
|
@@ -250,7 +256,7 @@ module Foreplay
|
|
250
256
|
steps.each do |step|
|
251
257
|
commands = build_commands step, instructions
|
252
258
|
|
253
|
-
commands.each { |command| puts "
|
259
|
+
commands.each { |command| puts "#{INDENT * 2}#{command}" unless step[:silent] }
|
254
260
|
end
|
255
261
|
end
|
256
262
|
|
@@ -258,7 +264,7 @@ module Foreplay
|
|
258
264
|
end
|
259
265
|
|
260
266
|
def build_commands step, instructions
|
261
|
-
puts "
|
267
|
+
puts "#{INDENT}#{(step[:commentary] || step[:command]).yellow}" unless step[:silent] == true
|
262
268
|
|
263
269
|
# Each step can be (1) a command or (2) a series of values to add to a file
|
264
270
|
if step.has_key? :key
|
data/lib/foreplay/version.rb
CHANGED
@@ -54,50 +54,10 @@ describe Foreplay::Deploy do
|
|
54
54
|
expect { Foreplay::Deploy.start([:deploy, 'production', '']) }.to raise_error(RuntimeError, /.*There was a problem starting an ssh session on web.example.com*/)
|
55
55
|
end
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
No instance is currently deployed
|
62
|
-
\e[0;33;49mSetting the port for the new instance to 50000\e[0m
|
63
|
-
echo 50000 > .foreplay/current_port
|
64
|
-
\e[0;33;49mCloning repository git@github.com:Xenapto/foreplay.git\e[0m
|
65
|
-
mkdir -p apps/foreplay && cd apps/foreplay && rm -rf 50000 && git clone git@github.com:Xenapto/foreplay.git 50000
|
66
|
-
\e[0;33;49mTrusting the .rvmrc file for the new instance\e[0m
|
67
|
-
rvm rvmrc trust 50000
|
68
|
-
\e[0;33;49mConfiguring the new instance\e[0m
|
69
|
-
cd 50000
|
70
|
-
\e[0;33;49mBuilding .env\e[0m
|
71
|
-
\e[0;33;49mBuilding .foreman\e[0m
|
72
|
-
\e[0;33;49mBuilding config/database.yml\e[0m
|
73
|
-
\e[0;33;49mUsing bundler to install the required gems\e[0m
|
74
|
-
bundle install
|
75
|
-
\e[0;33;49mSetting the current version of foreman to be the default\e[0m
|
76
|
-
sudo ln -f `which foreman` /usr/bin/foreman
|
77
|
-
\e[0;33;49mConverting foreplay-50000 to an upstart service\e[0m
|
78
|
-
sudo foreman export upstart /etc/init
|
79
|
-
\e[0;33;49mStarting the service\e[0m
|
80
|
-
sudo start foreplay-50000 || sudo restart foreplay-50000
|
81
|
-
\e[0;33;49mWaiting 60s to give service time to start\e[0m
|
82
|
-
sleep 60
|
83
|
-
\e[0;33;49mAdding firewall rule to direct incoming traffic on port 80 to port 50000\e[0m
|
84
|
-
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 50100
|
85
|
-
\e[0;33;49mRemoving previous firewall directing traffic to port 51000\e[0m
|
86
|
-
sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 51100
|
87
|
-
\e[0;33;49mSaving iptables rules to /etc/iptables/rules.v4\e[0m
|
88
|
-
sudo iptables-save > /etc/iptables/rules.v4
|
89
|
-
\e[0;33;49mSaving iptables rules to /etc/iptables.up.rules\e[0m
|
90
|
-
sudo iptables-save > /etc/iptables.up.rules
|
91
|
-
\e[0;33;49mCurrent firewall NAT configuration:\e[0m
|
92
|
-
sudo iptables-save -c | egrep REDIRECT --color=never
|
93
|
-
\e[0;33;49mStopping the previous instance\e[0m
|
94
|
-
sudo stop foreplay-51000 || echo 'No previous instance running'
|
95
|
-
Deployment configuration check was successful
|
96
|
-
OUTPUT
|
97
|
-
|
98
|
-
output.split("\n").reverse.each { |line| $stdout.should_receive(:puts).with(line) }
|
99
|
-
Foreplay::Deploy.start [:check, 'production', '']
|
100
|
-
end
|
57
|
+
it "should check the config" do
|
58
|
+
$stdout.should_receive(:puts).at_least(:once)
|
59
|
+
Foreplay::Deploy.start [:check, 'production', '']
|
60
|
+
end
|
101
61
|
|
102
62
|
it "should deploy to the environment" do
|
103
63
|
Net::SSH.should_receive(:start).with('web.example.com', 'fred', { :verbose => :warn, :password => 'trollope' }).and_yield(session)
|
@@ -126,8 +86,8 @@ OUTPUT
|
|
126
86
|
'sudo foreman export upstart /etc/init',
|
127
87
|
'sudo start foreplay-50000 || sudo restart foreplay-50000',
|
128
88
|
'sleep 60',
|
129
|
-
'sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port
|
130
|
-
'sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port
|
89
|
+
'sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 50000',
|
90
|
+
'sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 51000',
|
131
91
|
'sudo iptables-save > /etc/iptables/rules.v4',
|
132
92
|
'sudo iptables-save > /etc/iptables.up.rules',
|
133
93
|
'sudo iptables-save -c | egrep REDIRECT --color=never',
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreplay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-11-
|
12
|
+
date: 2013-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -224,7 +224,6 @@ files:
|
|
224
224
|
- features/support/env.rb
|
225
225
|
- foreplay.gemspec
|
226
226
|
- foreplay.rake
|
227
|
-
- foreplay.rb
|
228
227
|
- lib/foreplay.rb
|
229
228
|
- lib/foreplay/cli.rb
|
230
229
|
- lib/foreplay/deploy.rb
|
@@ -251,7 +250,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
251
250
|
version: '0'
|
252
251
|
segments:
|
253
252
|
- 0
|
254
|
-
hash: -
|
253
|
+
hash: -3290811328696495946
|
255
254
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
256
255
|
none: false
|
257
256
|
requirements:
|
@@ -260,7 +259,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
260
259
|
version: '0'
|
261
260
|
segments:
|
262
261
|
- 0
|
263
|
-
hash: -
|
262
|
+
hash: -3290811328696495946
|
264
263
|
requirements: []
|
265
264
|
rubyforge_project:
|
266
265
|
rubygems_version: 1.8.25
|
data/foreplay.rb
DELETED
@@ -1,246 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'yaml'
|
3
|
-
require 'net/ssh'
|
4
|
-
|
5
|
-
class Foreplay
|
6
|
-
class << self
|
7
|
-
def push check_only = false
|
8
|
-
environment = ENV['ENV']
|
9
|
-
config_file = "#{Rails.root}/config/foreplay.yml"
|
10
|
-
config_all = YAML.load(File.read(config_file))
|
11
|
-
|
12
|
-
# This environment
|
13
|
-
raise RuntimeError, "No deployment environment defined. Set the ENV environment variable." if environment.blank?
|
14
|
-
raise RuntimeError, "No deployment configuration defined for #{environment} environment. Check #{config_file}" unless config_all.has_key? environment
|
15
|
-
config = config_all[environment]
|
16
|
-
|
17
|
-
# Establish defaults
|
18
|
-
# First the default defaults
|
19
|
-
defaults = {
|
20
|
-
'name' => Rails.application.class.parent_name.underscore,
|
21
|
-
'environment' => environment,
|
22
|
-
'env' => { 'RAILS_ENV' => environment }
|
23
|
-
}
|
24
|
-
|
25
|
-
defaults = deep_merge_with_arrays(defaults, config_all['defaults']) if config_all.has_key? 'defaults' # Then the global defaults
|
26
|
-
defaults = deep_merge_with_arrays(defaults, config['defaults']) if config.has_key? 'defaults' # Then the defaults for this environment
|
27
|
-
|
28
|
-
config.each do |role, additional_instructions|
|
29
|
-
next if role == 'defaults' # 'defaults' is not a role
|
30
|
-
next unless ENV['ROLE'].blank? || ENV['ROLE'] == role # Only deploy to the role we've specified (or all roles if none is specified)
|
31
|
-
|
32
|
-
instructions = deep_merge_with_arrays(defaults, additional_instructions).symbolize_keys
|
33
|
-
instructions[:role] = role
|
34
|
-
required_keys = [:name, :environment, :role, :servers, :path, :repository]
|
35
|
-
|
36
|
-
required_keys.each { |key| raise RuntimeError, "Required key #{key} not found in instructions for #{environment} environment. Check #{config_file}" unless instructions.has_key? key }
|
37
|
-
|
38
|
-
deploy_role instructions unless check_only
|
39
|
-
end
|
40
|
-
|
41
|
-
puts check_only ? 'Deployment configuration check was successful' : 'Finished deployment'
|
42
|
-
end
|
43
|
-
|
44
|
-
def deploy_role instructions
|
45
|
-
servers = instructions[:servers]
|
46
|
-
puts "Deploying #{instructions[:name]} to #{servers.join(', ')} for the #{instructions[:role]} role in the #{instructions[:environment]} environment..." if servers.length > 1
|
47
|
-
servers.each { |server| deploy_to_server server, instructions }
|
48
|
-
end
|
49
|
-
|
50
|
-
def deploy_to_server server, instructions
|
51
|
-
name = instructions[:name]
|
52
|
-
environment = instructions[:environment]
|
53
|
-
role = instructions[:role]
|
54
|
-
path = instructions[:path]
|
55
|
-
repository = instructions[:repository]
|
56
|
-
user = instructions[:user]
|
57
|
-
|
58
|
-
instructions[:server] = server
|
59
|
-
|
60
|
-
puts "Deploying #{name} to #{server} for the #{role} role in the #{environment} environment"
|
61
|
-
|
62
|
-
# Substitute variables in the path
|
63
|
-
path.sub! '%u', user
|
64
|
-
path.sub! '%a', name
|
65
|
-
|
66
|
-
# Find out which port we're currently running on
|
67
|
-
steps = [ { :command => 'mkdir -p .foreplay && touch .foreplay/current_port && cat .foreplay/current_port', :silent => true } ]
|
68
|
-
|
69
|
-
current_port = execute_on_server(steps, instructions).strip!
|
70
|
-
puts "Current instance is using port #{current_port}"
|
71
|
-
|
72
|
-
# Switch ports
|
73
|
-
if current_port == '50000'
|
74
|
-
current_port = '51000'
|
75
|
-
former_port = '50000'
|
76
|
-
else
|
77
|
-
current_port = '50000'
|
78
|
-
former_port = '51000'
|
79
|
-
end
|
80
|
-
|
81
|
-
# Contents of .foreman file
|
82
|
-
current_service = '%s-%s' % [name, current_port]
|
83
|
-
former_service = '%s-%s' % [name, former_port]
|
84
|
-
|
85
|
-
instructions[:foreman]['app'] = current_service
|
86
|
-
instructions[:foreman]['port'] = current_port
|
87
|
-
instructions[:foreman]['user'] = user
|
88
|
-
|
89
|
-
# Commands to execute on remote server
|
90
|
-
steps = [
|
91
|
-
{ :command => "echo #{current_port} > .foreplay/current_port" },
|
92
|
-
{ :command => "mkdir -p #{path} && cd #{path} && rm -rf #{current_port} && git clone #{repository} #{current_port}",
|
93
|
-
:commentary => "Cloning repository #{repository}" },
|
94
|
-
{ :command => "rvm rvmrc trust #{current_port}" },
|
95
|
-
{ :command => "cd #{current_port}" },
|
96
|
-
{ :key => :env,
|
97
|
-
:delimiter => '=',
|
98
|
-
:prefix => '.',
|
99
|
-
:commentary => 'Building .env' },
|
100
|
-
{ :key => :foreman,
|
101
|
-
:delimiter => ': ',
|
102
|
-
:prefix => '.',
|
103
|
-
:commentary => 'Building .foreman' },
|
104
|
-
{ :key => :database,
|
105
|
-
:delimiter => ': ',
|
106
|
-
:suffix => '.yml',
|
107
|
-
:commentary => 'Building config/database.yml',
|
108
|
-
:before => ' ',
|
109
|
-
:header => "#{environment}:",
|
110
|
-
:path => 'config/' },
|
111
|
-
{ :command => "bundle install" },
|
112
|
-
{ :command => "sudo ln -f `which foreman` /usr/bin/foreman" },
|
113
|
-
{ :command => "sudo foreman export upstart /etc/init" },
|
114
|
-
{ :command => "sudo start #{current_service} || sudo restart #{current_service}",
|
115
|
-
:ignore_error => true },
|
116
|
-
{ :command => 'sleep 60',
|
117
|
-
:commentary => 'Waiting 60s to give service time to start' },
|
118
|
-
{ :command => "sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{current_port.to_i + 100}",
|
119
|
-
:commentary => "Adding firewall rule to direct incoming traffic on port 80 to port #{current_port}" },
|
120
|
-
{ :command => "sudo iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port #{former_port.to_i + 100}",
|
121
|
-
:commentary => "Removing previous firewall directing traffic to port #{former_port}",
|
122
|
-
:ignore_error => true },
|
123
|
-
{ :command => "sudo iptables -t nat -L | grep REDIRECT",
|
124
|
-
:ignore_error => true,
|
125
|
-
:commentary => "Current firewall NAT configuration:" },
|
126
|
-
{ :command => "sudo stop #{former_service} || echo 'No previous instance running'",
|
127
|
-
:ignore_error => true },
|
128
|
-
]
|
129
|
-
|
130
|
-
execute_on_server steps, instructions
|
131
|
-
end
|
132
|
-
|
133
|
-
def execute_on_server steps, instructions
|
134
|
-
server = instructions[:server]
|
135
|
-
user = instructions[:user]
|
136
|
-
password = instructions[:password]
|
137
|
-
keyfile = instructions[:keyfile]
|
138
|
-
key = instructions[:key]
|
139
|
-
|
140
|
-
keyfile.sub! '~' , ENV['HOME'] # Remote shell won't expand this for us
|
141
|
-
|
142
|
-
# SSH authentication methods
|
143
|
-
options = { :verbose => :warn }
|
144
|
-
|
145
|
-
if password.blank?
|
146
|
-
# If there's no password we must supply a private key
|
147
|
-
if key.blank?
|
148
|
-
raise RuntimeError, "No authentication methods supplied. You must supply a private key, key file or password in the configuration file" if keyfile.blank?
|
149
|
-
# Get the key from the key file
|
150
|
-
puts "Using private key from #{keyfile}"
|
151
|
-
key = File.read keyfile
|
152
|
-
else
|
153
|
-
puts "Using private key from the configuration file"
|
154
|
-
end
|
155
|
-
|
156
|
-
options[:key_data] = [key]
|
157
|
-
else
|
158
|
-
# Use the password supplied
|
159
|
-
options[:password] = password
|
160
|
-
end
|
161
|
-
|
162
|
-
# Capture output of last command to return to the calling routine
|
163
|
-
output = ''
|
164
|
-
|
165
|
-
# SSH connection
|
166
|
-
Net::SSH.start(server, user, options) do |ssh|
|
167
|
-
puts "Successfully connected to #{server}"
|
168
|
-
|
169
|
-
ssh.shell do |sh|
|
170
|
-
steps.each do |step|
|
171
|
-
# Output from this step
|
172
|
-
output = ''
|
173
|
-
previous = '' # We don't need or want the final CRLF
|
174
|
-
|
175
|
-
puts step[:commentary] || step[:command] unless step[:silent] == true
|
176
|
-
|
177
|
-
# Each step can be (1) a command or (2) a series of values to add to a file
|
178
|
-
if step.has_key? :key
|
179
|
-
step[:silent] = true
|
180
|
-
|
181
|
-
# Add values from the config file to a file on the remote machine
|
182
|
-
key = step[:key]
|
183
|
-
prefix = step[:prefix] || ''
|
184
|
-
suffix = step[:suffix] || ''
|
185
|
-
path = step[:path] || ''
|
186
|
-
before = step[:before] || ''
|
187
|
-
delimiter = step[:delimiter] || ''
|
188
|
-
after = step[:after] || ''
|
189
|
-
|
190
|
-
filename = '%s%s%s%s' % [path, prefix, key, suffix]
|
191
|
-
commands = step.has_key?(:header) ? ['echo "%s" >> %s' % [step[:header], filename]] : []
|
192
|
-
|
193
|
-
instructions[key].each { |k, v| commands << 'echo "%s%s%s%s%s" >> %s' % [before, k, delimiter, v, after, filename] }
|
194
|
-
else
|
195
|
-
# ...or just execute the command specified
|
196
|
-
commands = [step[:command]]
|
197
|
-
end
|
198
|
-
|
199
|
-
commands.each do |command|
|
200
|
-
process = sh.execute command
|
201
|
-
|
202
|
-
process.on_output do |p, o|
|
203
|
-
previous = o
|
204
|
-
output += previous
|
205
|
-
end
|
206
|
-
|
207
|
-
sh.wait!
|
208
|
-
|
209
|
-
if step[:ignore_error] == true || process.exit_status == 0
|
210
|
-
print "#{output}" unless step[:silent] == true
|
211
|
-
else
|
212
|
-
raise RuntimeError, output
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
output
|
220
|
-
end
|
221
|
-
|
222
|
-
# Returns a new hash with +hash+ and +other_hash+ merged recursively, including arrays.
|
223
|
-
#
|
224
|
-
# h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
|
225
|
-
# h2 = { x: { y: [7,8,9] }, z: 'xyz' }
|
226
|
-
# h1.deep_merge_with_arrays(h2)
|
227
|
-
# #=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
|
228
|
-
def deep_merge_with_arrays(hash, other_hash)
|
229
|
-
new_hash = hash.deep_dup
|
230
|
-
|
231
|
-
other_hash.each_pair do |k,v|
|
232
|
-
tv = new_hash[k]
|
233
|
-
|
234
|
-
if tv.is_a?(Hash) && v.is_a?(Hash)
|
235
|
-
new_hash[k] = deep_merge_with_arrays(tv, v)
|
236
|
-
elsif tv.is_a?(Array) || v.is_a?(Array)
|
237
|
-
new_hash[k] = Array.wrap(tv) + Array.wrap(v)
|
238
|
-
else
|
239
|
-
new_hash[k] = v
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
new_hash
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|