rest-ftp-daemon 0.435.2 → 0.501.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/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
|