pike 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +12 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +52 -0
- data/LICENSE +20 -0
- data/Pikefile.example +103 -0
- data/README.md +139 -0
- data/Rakefile +1 -0
- data/bin/pike +3 -0
- data/lib/pike/dsl/environment.rb +56 -0
- data/lib/pike/dsl/pikefile.rb +51 -0
- data/lib/pike/dsl/task.rb +101 -0
- data/lib/pike/env.rb +129 -0
- data/lib/pike/logger.rb +86 -0
- data/lib/pike/main.rb +275 -0
- data/lib/pike/rba/builder.rb +60 -0
- data/lib/pike/ssh/connection.rb +179 -0
- data/lib/pike/ssh/process.rb +34 -0
- data/lib/pike/ssh/runner.rb +115 -0
- data/lib/pike/tasks/command/local.rb +35 -0
- data/lib/pike/tasks/command/remote.rb +31 -0
- data/lib/pike/tasks/command.rb +150 -0
- data/lib/pike/tasks/task.rb +125 -0
- data/lib/pike/tasks/tasks.rb +168 -0
- data/lib/pike/version.rb +3 -0
- data/lib/pike.rb +56 -0
- data/pike.gemspec +33 -0
- data/script/build +7 -0
- data/spec/spec_helper.rb +6 -0
- metadata +160 -0
data/lib/pike/env.rb
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
module Pike
|
2
|
+
class Env
|
3
|
+
attr_reader \
|
4
|
+
:lifecycle, # Contains the lifecycle (an array of [tasks, params])
|
5
|
+
:variables, # Conains all environment specific variables
|
6
|
+
:name # Name of the environment
|
7
|
+
|
8
|
+
# Aboslute path to the bundle executable on the remote machine
|
9
|
+
attr_reader :bundler_prefix
|
10
|
+
|
11
|
+
|
12
|
+
##
|
13
|
+
## Constructor
|
14
|
+
##
|
15
|
+
|
16
|
+
def initialize(name, &block)
|
17
|
+
@name = name
|
18
|
+
@variables = {}
|
19
|
+
@lifecycle = []
|
20
|
+
DSL::Environment.load(self, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
##
|
25
|
+
## Called from the DSL to add a task to the lifecycle
|
26
|
+
##
|
27
|
+
|
28
|
+
def add_task(name, params = {})
|
29
|
+
@lifecycle << [name, params]
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
##
|
34
|
+
## Sets some internal variables
|
35
|
+
##
|
36
|
+
|
37
|
+
def prepare
|
38
|
+
# Set the release path
|
39
|
+
deploy_to = get_var(:deploy_to) + '/.pike/releases/'
|
40
|
+
set_var release_path: (deploy_to.gsub('//', '/') + Time.new.to_i.to_s + '/')
|
41
|
+
set_var root_dir: File.expand_path(Dir.pwd)
|
42
|
+
set_var build_dir: File.expand_path("#{Dir.pwd}/.pikebuild")
|
43
|
+
|
44
|
+
# Ensure the ssh connection works
|
45
|
+
SSH::Connection.connect get_var(:host), get_var(:user)
|
46
|
+
|
47
|
+
# Ensure sudo works if required
|
48
|
+
if get_var(:use_sudo)
|
49
|
+
SSH::Connection.try_sudo
|
50
|
+
end
|
51
|
+
|
52
|
+
# Get bundler path
|
53
|
+
pre = "[[ -s '/etc/profile.d/rvm.sh' ]] && source /etc/profile.d/rvm.sh"
|
54
|
+
@bundler_prefix = "#{pre} && "
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
##
|
59
|
+
## Runs a single task from that environment
|
60
|
+
##
|
61
|
+
def run_single_task(name)
|
62
|
+
prepare
|
63
|
+
|
64
|
+
task_to_run = nil
|
65
|
+
lifecycle.each do |task|
|
66
|
+
if task[0] == name
|
67
|
+
task_to_run = task
|
68
|
+
break
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
if task_to_run == nil
|
73
|
+
Main.error("Unkown task '#{name}'")
|
74
|
+
else
|
75
|
+
run_task(task_to_run[0], task_to_run[1])
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
##
|
81
|
+
## Run the complete lifecycle of the environment
|
82
|
+
##
|
83
|
+
|
84
|
+
def run_lifecycle
|
85
|
+
prepare
|
86
|
+
|
87
|
+
@lifecycle.each do |task|
|
88
|
+
run_task task[0], task[1]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
##
|
94
|
+
## Called from the DSL to set variables
|
95
|
+
##
|
96
|
+
|
97
|
+
def set_var(vars = {})
|
98
|
+
vars.keys.each do |key|
|
99
|
+
@variables[key] = vars[key]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
##
|
105
|
+
## Returns a variables value
|
106
|
+
##
|
107
|
+
|
108
|
+
def get_var(key)
|
109
|
+
@variables[key] || Main.get_var(key)
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
##
|
114
|
+
## Runs a task for that environment
|
115
|
+
##
|
116
|
+
|
117
|
+
def run_task(name, params)
|
118
|
+
Main.action "# Run task #{name}" do
|
119
|
+
task = Main.find_task(name)
|
120
|
+
|
121
|
+
if task
|
122
|
+
task.run(self, params)
|
123
|
+
else
|
124
|
+
raise "Task #{name} not found"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/pike/logger.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module Pike
|
2
|
+
class Logger
|
3
|
+
class << self
|
4
|
+
|
5
|
+
##
|
6
|
+
## Call this if Main.get(:log_file) is finally determined
|
7
|
+
##
|
8
|
+
|
9
|
+
def init
|
10
|
+
setup_logfile
|
11
|
+
|
12
|
+
log(@log_buffer.string) if @log_buffer
|
13
|
+
|
14
|
+
log
|
15
|
+
log("Timestamp: #{Time.now}")
|
16
|
+
log
|
17
|
+
log('Starting build ...')
|
18
|
+
log
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
##
|
23
|
+
## Logs a String or (if no param is given) a line break.
|
24
|
+
## Can be called before Logger.init, then everything will be buffered and written to the
|
25
|
+
## log file after it is initialized
|
26
|
+
##
|
27
|
+
|
28
|
+
def log(what = ' ')
|
29
|
+
if @log
|
30
|
+
log_target = @log
|
31
|
+
else
|
32
|
+
@log_buffer = StringIO.new unless @log_buffer
|
33
|
+
log_target = @log_buffer
|
34
|
+
end
|
35
|
+
|
36
|
+
log_target.puts "#{what}\n"
|
37
|
+
log_target.flush
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
##
|
42
|
+
## The banner or header for the log file containing some debug infos
|
43
|
+
##
|
44
|
+
|
45
|
+
def log_banner
|
46
|
+
log('#######################################')
|
47
|
+
log('# #')
|
48
|
+
log('# PIKE >> Intelligent Deployments #')
|
49
|
+
log('# #')
|
50
|
+
log('#######################################')
|
51
|
+
log
|
52
|
+
log("Pike version: #{Pike::VERSION.to_s}")
|
53
|
+
log("Ruby version: #{RUBY_VERSION}p#{RUBY_PATCHLEVEL} on #{RUBY_PLATFORM}")
|
54
|
+
log
|
55
|
+
log('Documentation: https://github.com/phortx/pike/wiki')
|
56
|
+
log('Issues: https://github.com/phortx/pike')
|
57
|
+
log
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
##
|
62
|
+
## Closes the log file
|
63
|
+
##
|
64
|
+
|
65
|
+
def close
|
66
|
+
@log.close if @log
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
private #-------------------------------------------------------------------------------------
|
72
|
+
|
73
|
+
##
|
74
|
+
## Setup the log file
|
75
|
+
##
|
76
|
+
|
77
|
+
def setup_logfile
|
78
|
+
log_file = Main.get_var(:log_file)
|
79
|
+
FileUtils.mkdir_p(File.dirname(log_file))
|
80
|
+
FileUtils.rm_f(log_file)
|
81
|
+
FileUtils.touch(log_file)
|
82
|
+
@log = File.open(log_file, 'w')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/pike/main.rb
ADDED
@@ -0,0 +1,275 @@
|
|
1
|
+
require 'pike/env'
|
2
|
+
require 'pike/version'
|
3
|
+
require 'pike/logger'
|
4
|
+
require 'pike/ssh/connection'
|
5
|
+
require 'pike/dsl/pikefile'
|
6
|
+
require 'pike/dsl/task'
|
7
|
+
require 'pike/dsl/environment'
|
8
|
+
require 'pike/tasks/task'
|
9
|
+
require 'pike/tasks/command'
|
10
|
+
require 'pike/rba/builder'
|
11
|
+
require 'fileutils'
|
12
|
+
require 'stringio'
|
13
|
+
|
14
|
+
# Main class manages the whole pike system
|
15
|
+
|
16
|
+
module Pike
|
17
|
+
class Main
|
18
|
+
class << self
|
19
|
+
attr_accessor :debug
|
20
|
+
|
21
|
+
attr_reader \
|
22
|
+
:env, # Current environment to deploy
|
23
|
+
|
24
|
+
# Hash of available environments
|
25
|
+
:envs,
|
26
|
+
|
27
|
+
# Hash of global variables
|
28
|
+
:variables,
|
29
|
+
|
30
|
+
# Hash with all available tasks
|
31
|
+
:tasks,
|
32
|
+
|
33
|
+
# The task the user wants to run, nil means default lifecycle for that env
|
34
|
+
:task_to_run,
|
35
|
+
|
36
|
+
# Dry run?
|
37
|
+
:dry_run,
|
38
|
+
|
39
|
+
# Verbose mode?
|
40
|
+
:verbose
|
41
|
+
|
42
|
+
|
43
|
+
##
|
44
|
+
## Constructor
|
45
|
+
##
|
46
|
+
|
47
|
+
def init(options)
|
48
|
+
@envs = {}
|
49
|
+
@variables = {}
|
50
|
+
@tasks = {}
|
51
|
+
@debug = options[:debug]
|
52
|
+
@task_to_run = nil
|
53
|
+
@dry_run = options[:dry_run]
|
54
|
+
@verbose = options[:verbose]
|
55
|
+
|
56
|
+
Logger.log_banner
|
57
|
+
|
58
|
+
# Variable defaults
|
59
|
+
set_var ({
|
60
|
+
branch: :master,
|
61
|
+
log_file: 'log/pike.log'
|
62
|
+
})
|
63
|
+
|
64
|
+
# Some pretty utf8 chars to illustrate some actions
|
65
|
+
@config_char = "\u26a1"
|
66
|
+
@environment_char = "\u2699"
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
##
|
71
|
+
## Run the deployment
|
72
|
+
##
|
73
|
+
|
74
|
+
def run
|
75
|
+
begin
|
76
|
+
# Step 1: Check if the Pikefile exists and load config
|
77
|
+
load_pikefile
|
78
|
+
|
79
|
+
# step 2: Internal stuff
|
80
|
+
Logger.init
|
81
|
+
|
82
|
+
# Step 3: Set environment
|
83
|
+
set_environment
|
84
|
+
|
85
|
+
# Step 4: Load tasks.rb
|
86
|
+
prepare
|
87
|
+
|
88
|
+
# Step 5: Run deployment lifecycle for the given environment
|
89
|
+
run_lifecycle
|
90
|
+
|
91
|
+
# Step 6: Close SSH connection
|
92
|
+
finalize
|
93
|
+
rescue Exception => e
|
94
|
+
Main.error(e.message, e.backtrace)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
##
|
100
|
+
## Load Pikefile
|
101
|
+
##
|
102
|
+
|
103
|
+
def load_pikefile
|
104
|
+
action "#{@config_char} Loading Pikefile" do
|
105
|
+
# Check if file exists
|
106
|
+
raise 'No Pikefile found' unless File.exist?(Dir.pwd + '/Pikefile')
|
107
|
+
|
108
|
+
# Load the Pikefile
|
109
|
+
DSL::Pikefile.load('Pikefile')
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
##
|
115
|
+
## Sets the @env variable depending on what the user provided
|
116
|
+
##
|
117
|
+
|
118
|
+
def set_environment
|
119
|
+
action "#{@config_char} Check given environment" do
|
120
|
+
@env = ARGV[0].to_sym
|
121
|
+
|
122
|
+
if @envs.include?(@env)
|
123
|
+
@env = @envs[@env]
|
124
|
+
Logger.log "Environment: #{@env.name}"
|
125
|
+
else
|
126
|
+
Logger.log "Unknown environment #{@env}. Please check you Pikefile."
|
127
|
+
raise "Unknown environment #{@env}. Please check you Pikefile."
|
128
|
+
end
|
129
|
+
|
130
|
+
if ARGV[1]
|
131
|
+
@task_to_run = ARGV[1].to_sym
|
132
|
+
Logger.log "Task: #{@task_to_run}"
|
133
|
+
end
|
134
|
+
|
135
|
+
@env
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
##
|
141
|
+
## Load tasks
|
142
|
+
##
|
143
|
+
|
144
|
+
def prepare
|
145
|
+
action "#{@config_char} Preparing ..." do
|
146
|
+
Logger.log("Loading tasks ...")
|
147
|
+
DSL::Pikefile.load(File.expand_path(File.dirname(__FILE__)) + '/tasks/tasks.rb')
|
148
|
+
|
149
|
+
true
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
##
|
155
|
+
## Run the lifecycle for the environment
|
156
|
+
##
|
157
|
+
|
158
|
+
def run_lifecycle
|
159
|
+
if @task_to_run
|
160
|
+
Logger.log "Run task #{@task_to_run} for env '#{@env.name}'"
|
161
|
+
action "#{@environment_char} Run task #{@task_to_run} for env '#{@env.name}'" do
|
162
|
+
@env.run_single_task(@task_to_run)
|
163
|
+
end
|
164
|
+
else
|
165
|
+
Logger.log "Run deployment lifecycle for env '#{@env.name}'"
|
166
|
+
action "#{@environment_char} Run deployment lifecycle for env '#{@env.name}'" do
|
167
|
+
@env.run_lifecycle
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
##
|
174
|
+
## Close ssh connection and logger
|
175
|
+
##
|
176
|
+
|
177
|
+
def finalize
|
178
|
+
Logger.log
|
179
|
+
Logger.log "Finished."
|
180
|
+
|
181
|
+
SSH::Connection.close
|
182
|
+
Logger.close
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
##
|
187
|
+
## Adds one or more variables (called from DSL::Pikefile.set)
|
188
|
+
##
|
189
|
+
|
190
|
+
def set_var(vars = {})
|
191
|
+
vars.keys.each do |key|
|
192
|
+
Logger.log "Set variable '#{key}' to '#{vars[key]}"
|
193
|
+
@variables[key] = vars[key]
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
##
|
199
|
+
## Get value of an variable (called from DSL::Pikefile.get)
|
200
|
+
##
|
201
|
+
|
202
|
+
def get_var(key)
|
203
|
+
@variables[key]
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
##
|
208
|
+
## Add a task (called from DSL::Pikefile.task)
|
209
|
+
##
|
210
|
+
|
211
|
+
def add_task(name, &block)
|
212
|
+
Logger.log "Adding task '#{name}'"
|
213
|
+
@tasks[name] = Task.new(name, &block)
|
214
|
+
end
|
215
|
+
|
216
|
+
|
217
|
+
##
|
218
|
+
## Add a environment (called from DSL::Pikefile.env)
|
219
|
+
##
|
220
|
+
def add_env(name, &block)
|
221
|
+
Logger.log "Adding environment '#{name}'"
|
222
|
+
@envs[name] = Env.new(name, &block)
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
##
|
227
|
+
## Find task by name and return
|
228
|
+
##
|
229
|
+
|
230
|
+
def find_task(task)
|
231
|
+
@tasks[task]
|
232
|
+
end
|
233
|
+
|
234
|
+
|
235
|
+
##
|
236
|
+
## Wrapper for step method to set @debug
|
237
|
+
##
|
238
|
+
|
239
|
+
def action(msg, vital = true, &block)
|
240
|
+
begin
|
241
|
+
step msg, vital: vital, debug: @debug do
|
242
|
+
yield block
|
243
|
+
end
|
244
|
+
rescue Exception => e
|
245
|
+
Main.error(e.message, e.backtrace)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
|
250
|
+
##
|
251
|
+
## Handles an error
|
252
|
+
##
|
253
|
+
|
254
|
+
def error(msg, trace = nil)
|
255
|
+
puts
|
256
|
+
puts
|
257
|
+
puts msg
|
258
|
+
puts
|
259
|
+
|
260
|
+
if @debug
|
261
|
+
puts trace || caller
|
262
|
+
end
|
263
|
+
|
264
|
+
puts
|
265
|
+
|
266
|
+
Logger.log
|
267
|
+
Logger.log
|
268
|
+
Logger.log "Error in task:"
|
269
|
+
Logger.log msg
|
270
|
+
Logger.log
|
271
|
+
exit 1
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems/package'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Pike
|
5
|
+
module RBA
|
6
|
+
class Builder
|
7
|
+
##
|
8
|
+
## Builds an .rba file
|
9
|
+
##
|
10
|
+
|
11
|
+
def self.build(target_file)
|
12
|
+
FileUtils.touch(target_file)
|
13
|
+
tarfile = File.open(target_file, 'w')
|
14
|
+
|
15
|
+
tar_stream = StringIO.new
|
16
|
+
tar_stream = build_tar_file(tar_stream)
|
17
|
+
gzipped_tar_stream = gzip(tar_stream)
|
18
|
+
|
19
|
+
tarfile.write gzipped_tar_stream.string
|
20
|
+
|
21
|
+
tarfile.close
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def self.build_tar_file(tarfile)
|
28
|
+
Gem::Package::TarWriter.new(tarfile) do |tar|
|
29
|
+
files = Dir.glob('**/*', File::FNM_DOTMATCH).reject! {|f| f =~ /^tmp|log/i || f =~ /^\.\.?$/ }
|
30
|
+
|
31
|
+
files.each do |file|
|
32
|
+
mode = File.stat(file).mode
|
33
|
+
relative_file = file.sub /^#{Regexp::escape(Dir.pwd)}\/?/, ''
|
34
|
+
|
35
|
+
if File.directory?(file)
|
36
|
+
tar.mkdir relative_file, mode
|
37
|
+
else
|
38
|
+
Logger.log " Adding file to rba: #{file}"
|
39
|
+
|
40
|
+
tar.add_file relative_file, mode do |tf|
|
41
|
+
File.open(file, "rb") { |f| tf.write f.read }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
return tarfile
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.gzip(stream)
|
51
|
+
gzipped_stream = StringIO.new
|
52
|
+
z = Zlib::GzipWriter.new(gzipped_stream)
|
53
|
+
z.write stream.string
|
54
|
+
z.close
|
55
|
+
|
56
|
+
return StringIO.new gzipped_stream.string
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'net/ssh/shell'
|
2
|
+
require 'net/scp'
|
3
|
+
require 'pike/ssh/runner'
|
4
|
+
|
5
|
+
module Pike
|
6
|
+
module SSH
|
7
|
+
class Connection
|
8
|
+
class << self
|
9
|
+
# Net::SSH session
|
10
|
+
attr_reader :session
|
11
|
+
|
12
|
+
# Current working directory
|
13
|
+
attr_reader :cwd
|
14
|
+
|
15
|
+
# Host we're connected with
|
16
|
+
attr_reader :host
|
17
|
+
|
18
|
+
# User which was used to authenticate
|
19
|
+
attr_reader :user
|
20
|
+
|
21
|
+
# Current state of the connection
|
22
|
+
attr_reader :state
|
23
|
+
|
24
|
+
# The sudo password for that connection
|
25
|
+
attr_accessor :sudo_password
|
26
|
+
|
27
|
+
|
28
|
+
##
|
29
|
+
## Connects via ssh to target host if not already connected
|
30
|
+
##
|
31
|
+
|
32
|
+
def connect(host, user)
|
33
|
+
@host = host
|
34
|
+
@user = user
|
35
|
+
@cwd = '~'
|
36
|
+
|
37
|
+
unless @session
|
38
|
+
Main.action "Connecting to #{host}" do
|
39
|
+
begin
|
40
|
+
@session = ::Net::SSH.start(@host, @user)
|
41
|
+
wait!
|
42
|
+
true
|
43
|
+
rescue Exception => e
|
44
|
+
Main.error(e.inspect)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
##
|
52
|
+
## Try's sudo to ensure the password prompt will not pop again
|
53
|
+
##
|
54
|
+
|
55
|
+
def try_sudo
|
56
|
+
if @session
|
57
|
+
Main.action "Trying sudo" do
|
58
|
+
result = run("sudo echo 'ok'")
|
59
|
+
|
60
|
+
if result.success?
|
61
|
+
if result.stdout.strip.end_with?('ok')
|
62
|
+
true
|
63
|
+
else
|
64
|
+
Main.error('Unexpected data received while trying sudo: ' + result.stderr)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
Main.error('sudo failed. Wrong password?')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
false
|
72
|
+
else
|
73
|
+
connection_error
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
##
|
79
|
+
## Copies a file via scp to the remote server
|
80
|
+
##
|
81
|
+
|
82
|
+
def scp(local, remote, host)
|
83
|
+
if ready?
|
84
|
+
Logger.log "Uploading file #{local} to #{host}:#{remote} ..."
|
85
|
+
|
86
|
+
begin
|
87
|
+
@session.scp.upload!(File.expand_path(local), remote)
|
88
|
+
rescue Exception => e
|
89
|
+
Main.error('Something went wrong with scp.', e)
|
90
|
+
end
|
91
|
+
else
|
92
|
+
connection_error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
##
|
98
|
+
## Executes a command
|
99
|
+
##
|
100
|
+
|
101
|
+
def run(cmd)
|
102
|
+
connection_error unless ready?
|
103
|
+
Runner.run(self, cmd)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
##
|
108
|
+
## Closes the connection
|
109
|
+
##
|
110
|
+
|
111
|
+
def close
|
112
|
+
if @session
|
113
|
+
begin
|
114
|
+
@session.close
|
115
|
+
rescue
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
##
|
122
|
+
## Wait method, wrapper for Net::SSH::Session.loopt
|
123
|
+
##
|
124
|
+
|
125
|
+
def wait!
|
126
|
+
@session.loop
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
##
|
131
|
+
## Checks if the class is ready to run commands
|
132
|
+
##
|
133
|
+
|
134
|
+
def ready?
|
135
|
+
@session != nil
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
|
140
|
+
##
|
141
|
+
## Changes the woring directory
|
142
|
+
##
|
143
|
+
|
144
|
+
def cd(new_cwd)
|
145
|
+
prc = run("cd #{new_cwd}")
|
146
|
+
|
147
|
+
if prc.success?
|
148
|
+
@cwd = new_cwd
|
149
|
+
else
|
150
|
+
Main.error("Can't change workind directory: #{new_cwd} (#{prc.stderr.strip})")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
##
|
156
|
+
## Wrapper for Session.open_channel
|
157
|
+
##
|
158
|
+
|
159
|
+
def open_channel(&method)
|
160
|
+
@session.open_channel &method
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
|
169
|
+
##
|
170
|
+
## Error for unestablished connections
|
171
|
+
##
|
172
|
+
|
173
|
+
def connection_error
|
174
|
+
Main.error('SSH connection is not ready yet. Call Pike::SSH::Connection.connect first.')
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|