pike 0.0.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 +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
|