rest-ftp-daemon 0.435.2 → 0.501.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +35 -29
- data/config.ru +1 -1
- data/defaults.yml +16 -12
- data/lib/rest-ftp-daemon.rb +1 -0
- data/lib/rest-ftp-daemon/api/config.rb +1 -2
- data/lib/rest-ftp-daemon/api/dashboard.rb +6 -4
- data/lib/rest-ftp-daemon/api/debug.rb +6 -5
- data/lib/rest-ftp-daemon/api/jobs.rb +1 -1
- data/lib/rest-ftp-daemon/api/root.rb +11 -10
- data/lib/rest-ftp-daemon/api/status.rb +1 -1
- data/lib/rest-ftp-daemon/constants.rb +12 -3
- data/lib/rest-ftp-daemon/counters.rb +1 -1
- data/lib/rest-ftp-daemon/entities/job.rb +1 -5
- data/lib/rest-ftp-daemon/entities/location.rb +4 -3
- data/lib/rest-ftp-daemon/entities/options.rb +1 -1
- data/lib/rest-ftp-daemon/exceptions.rb +1 -1
- data/lib/rest-ftp-daemon/helpers/api.rb +1 -1
- data/lib/rest-ftp-daemon/helpers/common.rb +1 -1
- data/lib/rest-ftp-daemon/helpers/views.rb +29 -10
- data/lib/rest-ftp-daemon/initialize.rb +1 -1
- data/lib/rest-ftp-daemon/job.rb +11 -13
- data/lib/rest-ftp-daemon/job_queue.rb +9 -10
- data/lib/rest-ftp-daemon/jobs/dummy.rb +1 -1
- data/lib/rest-ftp-daemon/jobs/errors.rb +13 -15
- data/lib/rest-ftp-daemon/jobs/transfer.rb +15 -15
- data/lib/rest-ftp-daemon/jobs/video.rb +7 -7
- data/lib/rest-ftp-daemon/launcher.rb +1 -1
- data/lib/rest-ftp-daemon/location.rb +91 -67
- data/lib/rest-ftp-daemon/metrics.rb +2 -2
- data/lib/rest-ftp-daemon/notification.rb +1 -1
- data/lib/rest-ftp-daemon/paginate.rb +1 -1
- data/lib/rest-ftp-daemon/remote/base.rb +8 -3
- data/lib/rest-ftp-daemon/remote/ftp.rb +18 -18
- data/lib/rest-ftp-daemon/remote/s3.rb +100 -41
- data/lib/rest-ftp-daemon/remote/sftp.rb +15 -15
- data/lib/rest-ftp-daemon/static/css/main.css +34 -4
- data/lib/rest-ftp-daemon/uri.rb +1 -1
- data/lib/rest-ftp-daemon/views/dashboard.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_counters.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_footer.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_header.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_jobs.haml +1 -2
- data/lib/rest-ftp-daemon/views/dashboard_rates.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_table.haml +8 -5
- data/lib/rest-ftp-daemon/views/dashboard_tokens.haml +1 -1
- data/lib/rest-ftp-daemon/views/dashboard_workers.haml +1 -1
- data/lib/rest-ftp-daemon/worker_pool.rb +2 -2
- data/lib/rest-ftp-daemon/workers/conchita.rb +1 -1
- data/lib/rest-ftp-daemon/workers/reporter.rb +1 -1
- data/lib/rest-ftp-daemon/workers/transfer.rb +3 -3
- data/lib/rest-ftp-daemon/workers/worker.rb +1 -1
- data/lib/shared/patch_file.rb +5 -0
- data/rest-ftp-daemon.gemspec +2 -2
- data/spec/spec_helper.rb +2 -1
- data/spec/support/request_helpers.rb +1 -1
- metadata +6 -5
@@ -50,10 +50,6 @@ module RestFtpDaemon
|
|
50
50
|
# Source and target #, :unless => Proc.new {|g| g.source_loc.nil?}
|
51
51
|
expose :source_loc, using: Entities::Location#, as: :source
|
52
52
|
expose :target_loc, using: Entities::Location#, as: :target
|
53
|
-
|
54
|
-
# expose :slots do |station,options|
|
55
|
-
# station.slots.map{ |slot| SlotEntity.new(slot).serializable_hash }
|
56
|
-
# end
|
57
53
|
end
|
58
54
|
end
|
59
|
-
end
|
55
|
+
end
|
@@ -4,8 +4,9 @@ module RestFtpDaemon
|
|
4
4
|
module Entities
|
5
5
|
class Location < Grape::Entity
|
6
6
|
|
7
|
-
expose :
|
8
|
-
|
7
|
+
expose :url
|
8
|
+
#, as: 'raw'
|
9
|
+
# expose :uri
|
9
10
|
expose :scheme
|
10
11
|
|
11
12
|
expose :host, unless: Proc.new {|obj| obj.host.nil?}
|
@@ -22,4 +23,4 @@ module RestFtpDaemon
|
|
22
23
|
|
23
24
|
end
|
24
25
|
end
|
25
|
-
end
|
26
|
+
end
|
@@ -40,6 +40,8 @@ module RestFtpDaemon
|
|
40
40
|
"success"
|
41
41
|
when URI::S3
|
42
42
|
"primary"
|
43
|
+
when URI::Generic
|
44
|
+
"info"
|
43
45
|
else
|
44
46
|
"default"
|
45
47
|
end
|
@@ -58,15 +60,6 @@ module RestFtpDaemon
|
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
|
-
def location_label uri
|
62
|
-
sprintf(
|
63
|
-
'<div class="transfer-type label label-%s" title="%s">%s</div>',
|
64
|
-
location_style(uri),
|
65
|
-
uri.to_s,
|
66
|
-
uri.class.name.split('::').last
|
67
|
-
)
|
68
|
-
end
|
69
|
-
|
70
63
|
def job_type job
|
71
64
|
# sprintf(
|
72
65
|
# '<span class="glyphicon glyphicon-%s" alt="%s"></span> %s',
|
@@ -118,6 +111,32 @@ module RestFtpDaemon
|
|
118
111
|
path.gsub(/\[([^\[]+)\]/, token_to_label('\1'))
|
119
112
|
end
|
120
113
|
|
114
|
+
def location_label loc
|
115
|
+
# sprintf(
|
116
|
+
# '<div class="transfer-type label label-%s" title="%s">%s</div>',
|
117
|
+
# location_style(loc.uri),
|
118
|
+
# loc.to_s,
|
119
|
+
# loc.uri.class.name.split('::').last
|
120
|
+
# )
|
121
|
+
sprintf(
|
122
|
+
'
|
123
|
+
<span class="label-group">
|
124
|
+
<span class="transfer-type label label-xs label-%s" title="%s">%s</span><span class="label label-simple" title="%s">%s</span>
|
125
|
+
</span>
|
126
|
+
',
|
127
|
+
location_style(loc.uri),
|
128
|
+
loc.to_s,
|
129
|
+
loc.uri.class.name.split('::').last,
|
130
|
+
loc.tokens.first,
|
131
|
+
loc.tokens.first,
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
# def token_highlight path
|
136
|
+
# return unless path.is_a? String
|
137
|
+
# path.gsub(/\[([^\[]+)\]/, token_to_label('\1'))
|
138
|
+
# end
|
139
|
+
|
121
140
|
def text_or_empty text
|
122
141
|
return "-" if text.nil? || text.empty?
|
123
142
|
text
|
@@ -125,4 +144,4 @@ module RestFtpDaemon
|
|
125
144
|
|
126
145
|
|
127
146
|
end
|
128
|
-
end
|
147
|
+
end
|
data/lib/rest-ftp-daemon/job.rb
CHANGED
@@ -85,7 +85,7 @@ module RestFtpDaemon
|
|
85
85
|
@target_loc = Location.new(params[:target])
|
86
86
|
|
87
87
|
# We're done!
|
88
|
-
log_info "
|
88
|
+
log_info "initialized", {
|
89
89
|
source: @source_loc.uri,
|
90
90
|
target: @target_loc.uri,
|
91
91
|
pool: @pool,
|
@@ -110,7 +110,7 @@ module RestFtpDaemon
|
|
110
110
|
set_status JOB_STATUS_QUEUED
|
111
111
|
set_error nil
|
112
112
|
client_notify :queued
|
113
|
-
log_info "
|
113
|
+
log_info "reset notify[queued] tentative[#{@tentatives}]"
|
114
114
|
end
|
115
115
|
|
116
116
|
# Process job
|
@@ -123,23 +123,23 @@ module RestFtpDaemon
|
|
123
123
|
@started_at = Time.now
|
124
124
|
|
125
125
|
# Notify we start working
|
126
|
-
log_info "
|
126
|
+
log_info "client_notify [started]"
|
127
127
|
current_signal = :started
|
128
128
|
set_status JOB_STATUS_WORKING
|
129
129
|
client_notify :started
|
130
130
|
|
131
131
|
# Before work
|
132
|
-
log_debug "
|
132
|
+
log_debug "do_before"
|
133
133
|
current_signal = :started
|
134
134
|
do_before
|
135
135
|
|
136
136
|
# Do the hard work
|
137
|
-
log_debug "
|
137
|
+
log_debug "do_work"
|
138
138
|
current_signal = :ended
|
139
139
|
do_work
|
140
140
|
|
141
141
|
# Finalize all this
|
142
|
-
log_debug "
|
142
|
+
log_debug "do_after"
|
143
143
|
current_signal = :ended
|
144
144
|
do_after
|
145
145
|
|
@@ -150,7 +150,7 @@ module RestFtpDaemon
|
|
150
150
|
else
|
151
151
|
# All done !
|
152
152
|
set_status JOB_STATUS_FINISHED
|
153
|
-
log_info "
|
153
|
+
log_info "client_notify [ended]"
|
154
154
|
client_notify :ended
|
155
155
|
end
|
156
156
|
|
@@ -217,7 +217,7 @@ module RestFtpDaemon
|
|
217
217
|
protected
|
218
218
|
|
219
219
|
def alert_common_method_called
|
220
|
-
log_error "
|
220
|
+
log_error "PLACEHOLDER METHOD CALLED"
|
221
221
|
end
|
222
222
|
|
223
223
|
private
|
@@ -289,25 +289,23 @@ module RestFtpDaemon
|
|
289
289
|
RestFtpDaemon::Notification.new @notify, payload
|
290
290
|
|
291
291
|
rescue StandardError => ex
|
292
|
-
log_error "
|
292
|
+
log_error "client_notify EXCEPTION: #{ex.inspect}"
|
293
293
|
end
|
294
294
|
|
295
295
|
def oops signal, exception, error = nil#, include_backtrace = false
|
296
296
|
# Find error code in ERRORS table
|
297
297
|
if error.nil?
|
298
298
|
error = ERRORS.key(exception.class)
|
299
|
-
# log_debug "Job.oops ERRORS: #{exception.class} > #{error}"
|
300
299
|
end
|
301
300
|
|
302
301
|
# Default error code derived from exception name
|
303
302
|
if error.nil?
|
304
303
|
error = exception_to_error(exception)
|
305
|
-
# log_debug "Job.oops derivated: #{exception.class} > #{error}"
|
306
304
|
include_backtrace = true
|
307
305
|
end
|
308
306
|
|
309
307
|
# Log backtrace ?
|
310
|
-
message = "
|
308
|
+
message = "oops signal[#{signal}] exception[#{exception.class}] error[#{error}] #{exception.message}"
|
311
309
|
if include_backtrace
|
312
310
|
log_error message, exception.backtrace
|
313
311
|
else
|
@@ -349,4 +347,4 @@ module RestFtpDaemon
|
|
349
347
|
add_transaction_tracer :initialize, category: :task
|
350
348
|
|
351
349
|
end
|
352
|
-
end
|
350
|
+
end
|
@@ -30,7 +30,7 @@ module RestFtpDaemon
|
|
30
30
|
|
31
31
|
# Identifiers generator
|
32
32
|
@prefix = identifier(JOB_IDENT_LEN)
|
33
|
-
log_info "
|
33
|
+
log_info "initialized (prefix: #{@prefix})"
|
34
34
|
end
|
35
35
|
|
36
36
|
def create_job params
|
@@ -42,7 +42,7 @@ module RestFtpDaemon
|
|
42
42
|
# If object not found, don't create a job !
|
43
43
|
unless klass && klass < Job
|
44
44
|
message = "can't create [#{klass_name}] for type [#{params[:type]}]"
|
45
|
-
log_error "
|
45
|
+
log_error "create_job: #{message}"
|
46
46
|
raise QueueCantCreateJob, message
|
47
47
|
end
|
48
48
|
|
@@ -53,7 +53,7 @@ module RestFtpDaemon
|
|
53
53
|
job_id = prefixed_id(@last_id)
|
54
54
|
|
55
55
|
# Instantiate it and return the now object
|
56
|
-
log_info "
|
56
|
+
log_info "create_job: creating [#{klass.name}] with ID [#{job_id}]"
|
57
57
|
job = klass.new(job_id, params)
|
58
58
|
|
59
59
|
# Push it on the queue
|
@@ -147,10 +147,10 @@ module RestFtpDaemon
|
|
147
147
|
|
148
148
|
def push job
|
149
149
|
# Check that item responds to "priorty" method
|
150
|
-
raise "
|
151
|
-
raise "
|
152
|
-
raise "
|
153
|
-
raise "
|
150
|
+
raise "push: job should respond to: priority" unless job.respond_to? :priority
|
151
|
+
raise "push: job should respond to: id" unless job.respond_to? :id
|
152
|
+
raise "push: job should respond to: pool" unless job.respond_to? :pool
|
153
|
+
raise "push: job should respond to: reset" unless job.respond_to? :reset
|
154
154
|
|
155
155
|
@mutex.synchronize do
|
156
156
|
# Get this job's pool & prepare queue of this pool
|
@@ -190,7 +190,6 @@ module RestFtpDaemon
|
|
190
190
|
@waitings[pool] ||= []
|
191
191
|
loop do
|
192
192
|
if myqueue.empty?
|
193
|
-
#puts "JobQueue.pop(#{pool}): empty"
|
194
193
|
raise ThreadError, "queue empty" if non_block
|
195
194
|
@waitings[pool].push Thread.current
|
196
195
|
@mutex.sleep
|
@@ -228,7 +227,7 @@ module RestFtpDaemon
|
|
228
227
|
|
229
228
|
# Compute oldest limit
|
230
229
|
time_limit = Time.now - maxage.to_i
|
231
|
-
log_info "
|
230
|
+
log_info "expire limit [#{time_limit}] status [#{status}]" if verbose
|
232
231
|
|
233
232
|
@mutex.synchronize do
|
234
233
|
# Delete jobs from the queue when they match status and age limits
|
@@ -269,4 +268,4 @@ module RestFtpDaemon
|
|
269
268
|
add_transaction_tracer :jobs_by_status, category: :task
|
270
269
|
|
271
270
|
end
|
272
|
-
end
|
271
|
+
end
|
@@ -5,12 +5,16 @@ require "net/ftp"
|
|
5
5
|
require 'streamio-ffmpeg'
|
6
6
|
|
7
7
|
module RestFtpDaemon
|
8
|
+
class InvalidWorkerNumber < BaseException; end
|
9
|
+
class QueueCantCreateJob < BaseException; end
|
10
|
+
class JobException < BaseException; end
|
11
|
+
class JobNotFound < BaseException; end
|
8
12
|
class Job
|
9
13
|
|
10
14
|
# Common errors
|
11
15
|
ERRORS = {
|
12
|
-
|
13
|
-
|
16
|
+
# oops_invalid_argument: Errno::EINVAL,
|
17
|
+
oops_runtime_error: RuntimeError,
|
14
18
|
|
15
19
|
job_timeout: RestFtpDaemon::JobTimeout,
|
16
20
|
source_not_supported: RestFtpDaemon::SourceUnsupported,
|
@@ -41,7 +45,10 @@ module RestFtpDaemon
|
|
41
45
|
ftp_proto_error: Net::FTPProtoError,
|
42
46
|
ftp_error: Net::FTPError,
|
43
47
|
|
44
|
-
|
48
|
+
sftp_exception: Net::SFTP::StatusException,
|
49
|
+
sftp_key_mismatch: Net::SSH::HostKeyMismatch,
|
50
|
+
sftp_auth_failed: Net::SSH::AuthenticationFailed,
|
51
|
+
sftp_openssl_error: OpenSSL::SSL::SSLError,
|
45
52
|
|
46
53
|
s3_no_such_waiter: Aws::Waiters::Errors::NoSuchWaiterError,
|
47
54
|
s3_failure_state_error: Aws::Waiters::Errors::FailureStateError,
|
@@ -49,30 +56,21 @@ module RestFtpDaemon
|
|
49
56
|
s3_waiter_unexpected: Aws::Waiters::Errors::UnexpectedError,
|
50
57
|
s3_waiter_failed: Aws::Waiters::Errors::WaiterFailed,
|
51
58
|
|
59
|
+
#s3_not_found: Aws::S3::Errors::NotFound,
|
52
60
|
s3_permanent_redirect: Aws::S3::Errors::PermanentRedirect,
|
53
61
|
s3_no_such_key: Aws::S3::Errors::NoSuchKey,
|
54
62
|
s3_no_such_bucket: Aws::S3::Errors::NoSuchBucket,
|
55
63
|
s3_no_such_upload: Aws::S3::Errors::NoSuchUpload,
|
56
64
|
s3_error: Aws::S3::Errors::ServiceError,
|
57
65
|
|
58
|
-
sftp_exception: Net::SFTP::StatusException,
|
59
|
-
sftp_key_mismatch: Net::SSH::HostKeyMismatch,
|
60
|
-
sftp_auth_failed: Net::SSH::AuthenticationFailed,
|
61
|
-
sftp_openssl_error: OpenSSL::SSL::SSLError,
|
62
|
-
|
63
66
|
video_missing_binary: RestFtpDaemon::VideoMissingBinary,
|
64
67
|
video_movie_error: RestFtpDaemon::VideoMovieError,
|
68
|
+
video_ffmpeg_error: FFMPEG::Error,
|
65
69
|
|
66
70
|
# rescue Encoding::UndefinedConversionError => exception
|
67
71
|
# return oops :ended, exception, "encoding_error", true
|
68
72
|
}
|
69
73
|
|
70
|
-
class InvalidWorkerNumber < BaseException; end
|
71
|
-
class QueueCantCreateJob < BaseException; end
|
72
|
-
class JobException < BaseException; end
|
73
|
-
class JobNotFound < BaseException; end
|
74
|
-
|
75
|
-
|
76
74
|
|
77
75
|
end
|
78
|
-
end
|
76
|
+
end
|
@@ -21,20 +21,20 @@ module RestFtpDaemon
|
|
21
21
|
# Prepare remote object
|
22
22
|
case target_uri
|
23
23
|
when URI::FTP
|
24
|
-
log_info "
|
24
|
+
log_info "do_before target_method FTP"
|
25
25
|
@remote = Remote::RemoteFTP.new @target_loc, log_context, @config[:debug_ftp]
|
26
26
|
when URI::FTPES, URI::FTPS
|
27
|
-
log_info "
|
27
|
+
log_info "do_before target_method FTPES/FTPS"
|
28
28
|
@remote = Remote::RemoteFTP.new @target_loc, log_context, @config[:debug_ftps], :ftpes
|
29
29
|
when URI::SFTP
|
30
|
-
log_info "
|
30
|
+
log_info "do_before target_method SFTP"
|
31
31
|
@remote = Remote::RemoteSFTP.new @target_loc, log_context, @config[:debug_sftp]
|
32
32
|
when URI::S3
|
33
|
-
log_info "
|
33
|
+
log_info "do_before target_method S3"
|
34
34
|
@remote = Remote::RemoteS3.new @target_loc, log_context, @config[:debug_s3]
|
35
35
|
else
|
36
36
|
message = "unknown scheme [#{@target_loc.scheme}] [#{target_uri.class.name}]"
|
37
|
-
log_info "
|
37
|
+
log_info "do_before #{message}"
|
38
38
|
raise RestFtpDaemon::TargetUnsupported, message
|
39
39
|
end
|
40
40
|
|
@@ -48,10 +48,10 @@ module RestFtpDaemon
|
|
48
48
|
def do_work
|
49
49
|
# Scan local source files from disk
|
50
50
|
set_status JOB_STATUS_CHECKING_SRC
|
51
|
-
sources = @source_loc.
|
51
|
+
sources = @source_loc.local_files
|
52
52
|
set_info INFO_SOURCE_COUNT, sources.size
|
53
53
|
set_info INFO_SOURCE_FILES, sources.collect(&:name)
|
54
|
-
log_info "
|
54
|
+
log_info "do_work sources #{sources.collect(&:name)}"
|
55
55
|
raise RestFtpDaemon::SourceNotFound if sources.empty?
|
56
56
|
|
57
57
|
# Guess target file name, and fail if present while we matched multiple sources
|
@@ -63,7 +63,8 @@ module RestFtpDaemon
|
|
63
63
|
|
64
64
|
# Prepare target path or build it if asked
|
65
65
|
set_status JOB_STATUS_CHDIR
|
66
|
-
|
66
|
+
#log_info "do_work chdir_or_create #{@target_loc.filedir}"
|
67
|
+
@remote.chdir_or_create @target_loc.filedir, @mkdir
|
67
68
|
|
68
69
|
# Compute total files size
|
69
70
|
@transfer_total = sources.collect(&:size).sum
|
@@ -95,7 +96,7 @@ module RestFtpDaemon
|
|
95
96
|
|
96
97
|
def do_after
|
97
98
|
# Close FTP connexion and free up memory
|
98
|
-
log_info "
|
99
|
+
log_info "do_after close connexion, update status and counters"
|
99
100
|
@remote.close
|
100
101
|
|
101
102
|
# Free @remote object
|
@@ -117,14 +118,14 @@ module RestFtpDaemon
|
|
117
118
|
raise RestFtpDaemon::AssertionFailed, "remote_upload/target" if target.nil?
|
118
119
|
|
119
120
|
# Use source filename if target path provided none (typically with multiple sources)
|
120
|
-
log_info "
|
121
|
+
log_info "remote_upload temp[#{@tempfile}] source[#{source.path}] target[#{target.path}]"
|
121
122
|
set_info INFO_SOURCE_CURRENT, source.name
|
122
123
|
|
123
124
|
# Remove any existing version if present, or check if it's there
|
124
125
|
if @overwrite
|
125
126
|
@remote.remove! target
|
126
|
-
elsif size = @remote.
|
127
|
-
log_debug "
|
127
|
+
elsif (size = @remote.size_if_exists(target)) # won't be triggered when NIL or 0 is returned
|
128
|
+
log_debug "remote_upload file exists ! (#{format_bytes size, 'B'})"
|
128
129
|
raise RestFtpDaemon::TargetFileExists
|
129
130
|
end
|
130
131
|
|
@@ -134,7 +135,6 @@ module RestFtpDaemon
|
|
134
135
|
|
135
136
|
# Start the transfer, update job status after each block transfer
|
136
137
|
set_status JOB_STATUS_UPLOADING
|
137
|
-
log_debug "JobTransfer.remote_upload source[#{source.path}] temp[#{@tempfile}]"
|
138
138
|
@remote.upload source, target, @tempfile do |transferred, name|
|
139
139
|
# Update transfer statistics
|
140
140
|
update_progress transferred, name
|
@@ -192,7 +192,7 @@ module RestFtpDaemon
|
|
192
192
|
format_bytes(@current_bitrate.round(0), "bps")
|
193
193
|
]
|
194
194
|
stack2 = stack.map { |txt| ("%#{LOG_PIPE_LEN.to_i}s" % txt) }.join("\t")
|
195
|
-
|
195
|
+
log_info "progress #{stack2} \t#{name}"
|
196
196
|
|
197
197
|
# Prepare and send notification
|
198
198
|
client_notify :progress, status: {
|
@@ -233,4 +233,4 @@ module RestFtpDaemon
|
|
233
233
|
# add_transaction_tracer :prepare, category: :task
|
234
234
|
# add_transaction_tracer :run, category: :task
|
235
235
|
|
236
|
-
end
|
236
|
+
end
|