rest-ftp-daemon 0.6 → 0.9.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.
- data/Gemfile +8 -1
- data/Gemfile.lock +57 -54
- data/README.md +26 -116
- data/Rakefile +49 -1
- data/VERSION +1 -0
- data/bin/rest-ftp-daemon +17 -37
- data/lib/config.rb +3 -0
- data/lib/config.ru +11 -0
- data/lib/errors.rb +12 -0
- data/lib/extend_threads.rb +14 -0
- data/lib/rest-ftp-daemon.rb +304 -18
- data/rest-ftp-daemon.gemspec +62 -31
- metadata +46 -100
- checksums.yaml +0 -15
- data/.gitignore +0 -6
- data/config.ru +0 -14
- data/lib/rest-ftp-daemon/api/defaults.rb +0 -76
- data/lib/rest-ftp-daemon/api/jobs.rb +0 -151
- data/lib/rest-ftp-daemon/api/root.rb +0 -129
- data/lib/rest-ftp-daemon/api/workers.rb +0 -49
- data/lib/rest-ftp-daemon/common.rb +0 -49
- data/lib/rest-ftp-daemon/config.rb +0 -24
- data/lib/rest-ftp-daemon/exceptions.rb +0 -26
- data/lib/rest-ftp-daemon/job.rb +0 -246
- data/lib/rest-ftp-daemon/job_queue.rb +0 -105
- data/lib/rest-ftp-daemon/logger.rb +0 -7
- data/lib/rest-ftp-daemon/notification.rb +0 -82
- data/lib/rest-ftp-daemon/static/css/bootstrap.min.css +0 -5
- data/lib/rest-ftp-daemon/views/dashboard.haml +0 -86
- data/lib/rest-ftp-daemon/views/dashboard_jobs.haml +0 -75
- data/lib/rest-ftp-daemon/views/index.haml +0 -116
- data/lib/rest-ftp-daemon/worker_pool.rb +0 -63
- data/rest-ftp-daemon.yml.sample +0 -15
@@ -1,76 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require 'grape'
|
3
|
-
SIZE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB" ]
|
4
|
-
|
5
|
-
|
6
|
-
module RestFtpDaemon
|
7
|
-
module API
|
8
|
-
module Defaults
|
9
|
-
extend ActiveSupport::Concern
|
10
|
-
|
11
|
-
included do
|
12
|
-
#version 'v1', using: :header, vendor: 'ftven'
|
13
|
-
format :json
|
14
|
-
do_not_route_head!
|
15
|
-
do_not_route_options!
|
16
|
-
|
17
|
-
# before do
|
18
|
-
# header['Access-Control-Allow-Origin'] = '*'
|
19
|
-
# header['Access-Control-Request-Method'] = '*'
|
20
|
-
# end
|
21
|
-
|
22
|
-
# Handle authentication
|
23
|
-
# http_basic do |username, password|
|
24
|
-
# User.authenticate!(username, password)
|
25
|
-
# end
|
26
|
-
|
27
|
-
# # global handler for simple not found case
|
28
|
-
# rescue_from ActiveRecord::RecordNotFound do |e|
|
29
|
-
# error_response(message: e.message, status: 404)
|
30
|
-
# end
|
31
|
-
|
32
|
-
# # global exception handler, used for error notifications
|
33
|
-
# rescue_from :all do |e|
|
34
|
-
# if Rails.env.development?
|
35
|
-
# raise e
|
36
|
-
# else
|
37
|
-
# Raven.capture_exception(e)
|
38
|
-
# error_response(message: "Internal server error", status: 500)
|
39
|
-
# end
|
40
|
-
# end
|
41
|
-
|
42
|
-
# # HTTP header based authentication
|
43
|
-
# before do
|
44
|
-
# error!('Unauthorized', 401) unless headers['Authorization'] == "some token"
|
45
|
-
# end
|
46
|
-
|
47
|
-
helpers do
|
48
|
-
|
49
|
-
def format_nice_bytes( number )
|
50
|
-
return "Ø" if number.nil? || number.zero?
|
51
|
-
index = ( Math.log( number ) / Math.log( 2 ) ).to_i / 10
|
52
|
-
converted = number.to_i / ( 1024 ** index )
|
53
|
-
"#{converted} #{SIZE_UNITS[index]}"
|
54
|
-
end
|
55
|
-
|
56
|
-
def api_error exception
|
57
|
-
{
|
58
|
-
:error => exception.class,
|
59
|
-
:errmsg => exception.message,
|
60
|
-
:backtrace => exception.backtrace.first,
|
61
|
-
#:backtrace => exception.backtrace,
|
62
|
-
}
|
63
|
-
end
|
64
|
-
|
65
|
-
def render name, values={}
|
66
|
-
template = File.read("#{APP_ROOT}/lib/#{APP_NAME}/views/#{name.to_s}.haml")
|
67
|
-
haml_engine = Haml::Engine.new(template)
|
68
|
-
haml_engine.render(binding, values)
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,151 +0,0 @@
|
|
1
|
-
module RestFtpDaemon
|
2
|
-
module API
|
3
|
-
|
4
|
-
class Jobs < Grape::API
|
5
|
-
include RestFtpDaemon::API::Defaults
|
6
|
-
logger ActiveSupport::Logger.new Settings.logs.api, 'daily' unless Settings.logs.api.nil?
|
7
|
-
|
8
|
-
params do
|
9
|
-
optional :overwrite, type: Integer, default: false
|
10
|
-
end
|
11
|
-
|
12
|
-
helpers do
|
13
|
-
|
14
|
-
def threads_with_id job_id
|
15
|
-
$threads.list.select do |thread|
|
16
|
-
next unless thread[:job].is_a? Job
|
17
|
-
thread[:job].id == job_id
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def job_describe job_id
|
22
|
-
raise RestFtpDaemon::JobNotFound if ($queue.queued_size==0 && $queue.popped_size==0)
|
23
|
-
|
24
|
-
# Find job with this id
|
25
|
-
found = $queue.all.select { |job| job.id == job_id }.first
|
26
|
-
raise RestFtpDaemon::JobNotFound if found.nil?
|
27
|
-
raise RestFtpDaemon::JobNotFound unless found.is_a? Job
|
28
|
-
|
29
|
-
# Return job description
|
30
|
-
found.describe
|
31
|
-
end
|
32
|
-
|
33
|
-
# def job_delete job_id
|
34
|
-
# end
|
35
|
-
|
36
|
-
def job_list
|
37
|
-
$queue.all.map do |item|
|
38
|
-
next unless item.is_a? Job
|
39
|
-
item.describe
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
desc "Get information about a specific job"
|
46
|
-
params do
|
47
|
-
requires :id, type: Integer, desc: "job id"
|
48
|
-
end
|
49
|
-
get ':id' do
|
50
|
-
info "GET /jobs/#{params[:id]}"
|
51
|
-
begin
|
52
|
-
response = job_describe params[:id].to_i
|
53
|
-
rescue RestFtpDaemon::JobNotFound => exception
|
54
|
-
status 404
|
55
|
-
api_error exception
|
56
|
-
rescue RestFtpDaemonException => exception
|
57
|
-
status 500
|
58
|
-
api_error exception
|
59
|
-
rescue Exception => exception
|
60
|
-
status 501
|
61
|
-
api_error exception
|
62
|
-
else
|
63
|
-
status 200
|
64
|
-
response
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
# Delete jobs
|
69
|
-
desc "Kill and remove a specific job"
|
70
|
-
delete ':id' do
|
71
|
-
info "DELETE /jobs/#{params[:name]}"
|
72
|
-
status 501
|
73
|
-
# begin
|
74
|
-
# response = job_delete params[:id].to_i
|
75
|
-
# rescue RestFtpDaemon::JobNotFound => exception
|
76
|
-
# status 404
|
77
|
-
# api_error exception
|
78
|
-
# rescue RestFtpDaemonException => exception
|
79
|
-
# status 500
|
80
|
-
# api_error exception
|
81
|
-
# rescue Exception => exception
|
82
|
-
# status 501
|
83
|
-
# api_error exception
|
84
|
-
# else
|
85
|
-
# status 200
|
86
|
-
# response
|
87
|
-
# end
|
88
|
-
end
|
89
|
-
|
90
|
-
# List jobs
|
91
|
-
desc "Get a list of jobs"
|
92
|
-
get do
|
93
|
-
info "GET /jobs"
|
94
|
-
begin
|
95
|
-
response = job_list
|
96
|
-
rescue RestFtpDaemonException => exception
|
97
|
-
status 501
|
98
|
-
api_error exception
|
99
|
-
rescue Exception => exception
|
100
|
-
status 501
|
101
|
-
api_error exception
|
102
|
-
else
|
103
|
-
status 200
|
104
|
-
response
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
|
109
|
-
# Spawn a new thread for this new job
|
110
|
-
desc "Create a new job"
|
111
|
-
post do
|
112
|
-
info "POST /jobs: #{request.body.read}"
|
113
|
-
begin
|
114
|
-
# Extract params
|
115
|
-
request.body.rewind
|
116
|
-
params = JSON.parse request.body.read
|
117
|
-
|
118
|
-
# Create a new job
|
119
|
-
job_id = $last_worker_id += 1
|
120
|
-
job = Job.new(job_id, params)
|
121
|
-
|
122
|
-
# And psuh it to the queue
|
123
|
-
$queue.push job
|
124
|
-
|
125
|
-
# Later: start it asynchronously
|
126
|
-
#job.future.process
|
127
|
-
|
128
|
-
rescue JSON::ParserError => exception
|
129
|
-
status 406
|
130
|
-
api_error exception
|
131
|
-
rescue RestFtpDaemonException => exception
|
132
|
-
status 412
|
133
|
-
api_error exception
|
134
|
-
rescue Exception => exception
|
135
|
-
status 501
|
136
|
-
api_error exception
|
137
|
-
else
|
138
|
-
status 201
|
139
|
-
job.describe
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
protected
|
144
|
-
|
145
|
-
def progname
|
146
|
-
"API::Jobs"
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
@@ -1,129 +0,0 @@
|
|
1
|
-
require 'haml'
|
2
|
-
require "facter"
|
3
|
-
require "sys/cpu"
|
4
|
-
|
5
|
-
|
6
|
-
module RestFtpDaemon
|
7
|
-
module API
|
8
|
-
|
9
|
-
class Root < Grape::API
|
10
|
-
include RestFtpDaemon::API::Defaults
|
11
|
-
logger ActiveSupport::Logger.new Settings.logs.api, 'daily' unless Settings.logs.api.nil?
|
12
|
-
#add_swagger_documentation
|
13
|
-
|
14
|
-
mount RestFtpDaemon::API::Jobs => '/jobs'
|
15
|
-
# mount RestFtpDaemon::API::Workers => '/workers'
|
16
|
-
|
17
|
-
helpers do
|
18
|
-
def info message, level = 0
|
19
|
-
Root.logger.add(Logger::INFO, "#{' '*level} #{message}", "API::Root")
|
20
|
-
end
|
21
|
-
|
22
|
-
def job_list_by_status
|
23
|
-
statuses = {}
|
24
|
-
alljobs = $queue.all.map do |item|
|
25
|
-
next unless item.is_a? Job
|
26
|
-
statuses[item.get_status] ||= 0
|
27
|
-
statuses[item.get_status] +=1
|
28
|
-
end
|
29
|
-
|
30
|
-
statuses
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
######################################################################
|
36
|
-
####### INIT
|
37
|
-
######################################################################
|
38
|
-
def initialize
|
39
|
-
$last_worker_id = 0
|
40
|
-
super
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
######################################################################
|
46
|
-
####### API DEFINITION
|
47
|
-
######################################################################
|
48
|
-
|
49
|
-
# Server global status
|
50
|
-
get '/' do
|
51
|
-
# Prepare data
|
52
|
-
@jobs_all = $queue.all
|
53
|
-
#@jobs_all_size = $queue.all_size
|
54
|
-
#@jobs_all = $queue.all_size
|
55
|
-
|
56
|
-
# Initialize UsageWatch
|
57
|
-
Facter.loadfacts
|
58
|
-
@info_load = Sys::CPU.load_avg.first.to_f
|
59
|
-
@info_procs = (Facter.value :processorcount).to_i
|
60
|
-
@info_ipaddr = Facter.value(:ipaddress)
|
61
|
-
@info_memfree = Facter.value(:memoryfree)
|
62
|
-
|
63
|
-
|
64
|
-
# Compute normalized load
|
65
|
-
# puts "info_procs: #{info_procs}"
|
66
|
-
if @info_procs.zero?
|
67
|
-
@info_norm = "N/A"
|
68
|
-
else
|
69
|
-
@info_norm = (100 * @info_load / @info_procs).round(1)
|
70
|
-
end
|
71
|
-
|
72
|
-
# Compute total transferred
|
73
|
-
@total_transferred = 0
|
74
|
-
@jobs_all.each do |job|
|
75
|
-
sent = job.get(:file_sent)
|
76
|
-
@total_transferred += sent unless sent.nil?
|
77
|
-
end
|
78
|
-
|
79
|
-
# Compile haml template
|
80
|
-
@name = "Test"
|
81
|
-
output = render :dashboard
|
82
|
-
|
83
|
-
# Send response
|
84
|
-
env['api.format'] = :html
|
85
|
-
format "html"
|
86
|
-
status 200
|
87
|
-
content_type "text/html"
|
88
|
-
body output
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
# Server global status
|
93
|
-
get '/index.json' do
|
94
|
-
info "GET /"
|
95
|
-
status 200
|
96
|
-
return {
|
97
|
-
hostname: `hostname`.chomp,
|
98
|
-
version: Settings.version,
|
99
|
-
config: Settings.to_hash,
|
100
|
-
started: APP_STARTED,
|
101
|
-
uptime: (Time.now - APP_STARTED).round(1),
|
102
|
-
status: job_list_by_status,
|
103
|
-
queue_size: $queue.all_size,
|
104
|
-
jobs_queued: $queue.queued.collect(&:id),
|
105
|
-
jobs_popped: $queue.popped.collect(&:id),
|
106
|
-
routes: RestFtpDaemon::API::Root::routes,
|
107
|
-
}
|
108
|
-
end
|
109
|
-
|
110
|
-
# Server test
|
111
|
-
get '/debug' do
|
112
|
-
info "GET /debug/"
|
113
|
-
begin
|
114
|
-
raise RestFtpDaemon::DummyException
|
115
|
-
rescue RestFtpDaemon::RestFtpDaemonException => exception
|
116
|
-
status 501
|
117
|
-
api_error exception
|
118
|
-
rescue Exception => exception
|
119
|
-
status 501
|
120
|
-
api_error exception
|
121
|
-
else
|
122
|
-
status 200
|
123
|
-
{}
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# module RestFtpDaemon
|
2
|
-
# module API
|
3
|
-
|
4
|
-
# class Workers < Grape::API
|
5
|
-
# include RestFtpDaemon::API::Defaults
|
6
|
-
# logger ActiveSupport::Logger.new Settings.logs.api, 'daily' unless Settings.logs.api.nil?
|
7
|
-
|
8
|
-
# helpers do
|
9
|
-
# def info message, level = 0
|
10
|
-
# Jobs.logger.add(Logger::INFO, "#{' '*level} #{message}", "API::Workers")
|
11
|
-
# end
|
12
|
-
|
13
|
-
# def worker_list
|
14
|
-
# return {
|
15
|
-
# busy: $pool.busy_size,
|
16
|
-
# idle: $pool.idle_size,
|
17
|
-
# to_s: $pool.to_s,
|
18
|
-
# }
|
19
|
-
# #return $workers.list.size
|
20
|
-
# $workers.list.map do |thread|
|
21
|
-
# #next unless thread[:job].is_a? Worker
|
22
|
-
# "worker"
|
23
|
-
# #thread[:worker].inspect
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
|
27
|
-
# end
|
28
|
-
|
29
|
-
# # List jobs
|
30
|
-
# desc "Get a list of workers"
|
31
|
-
# get do
|
32
|
-
# info "GET /workers"
|
33
|
-
# begin
|
34
|
-
# response = worker_list
|
35
|
-
# rescue RestFtpDaemonException => exception
|
36
|
-
# status 501
|
37
|
-
# api_error exception
|
38
|
-
# rescue Exception => exception
|
39
|
-
# status 501
|
40
|
-
# api_error exception
|
41
|
-
# else
|
42
|
-
# status 200
|
43
|
-
# response
|
44
|
-
# end
|
45
|
-
# end
|
46
|
-
|
47
|
-
# end
|
48
|
-
# end
|
49
|
-
# end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
module RestFtpDaemon
|
2
|
-
|
3
|
-
class Common
|
4
|
-
|
5
|
-
protected
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
# Logger
|
9
|
-
@logger = ActiveSupport::Logger.new Settings.logs.workers, 'daily' unless Settings.logs.workers.nil?
|
10
|
-
end
|
11
|
-
|
12
|
-
def id
|
13
|
-
end
|
14
|
-
|
15
|
-
def progname
|
16
|
-
end
|
17
|
-
|
18
|
-
def info message, level = 0
|
19
|
-
# progname = "Job [#{id}]" unless id.nil?
|
20
|
-
# progname = "Worker [#{id}]" unless worker_id.nil?
|
21
|
-
@logger.add(Logger::INFO, "#{' '*(level+1)} #{message}", progname)
|
22
|
-
end
|
23
|
-
|
24
|
-
def notify signal, error = 0, status = {}
|
25
|
-
# Skip is not callback URL defined
|
26
|
-
url = get :notify
|
27
|
-
if url.nil?
|
28
|
-
info "Skipping notification (no valid url provided) sig[#{signal}] e[#{error}] s#{status.inspect}"
|
29
|
-
return
|
30
|
-
end
|
31
|
-
|
32
|
-
# Build notification
|
33
|
-
n = RestFtpDaemon::Notification.new
|
34
|
-
n.job_id = id
|
35
|
-
n.url = url
|
36
|
-
n.signal = signal
|
37
|
-
n.error = error.inspect
|
38
|
-
n.status = status
|
39
|
-
|
40
|
-
# Now, send the notification
|
41
|
-
info "Queuing notification key[#{n.key}] sig[#{signal}] url[#{url}]"
|
42
|
-
Thread.new(n) do |thread|
|
43
|
-
n.notify
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'settingslogic'
|
2
|
-
DEVELOPMENT = false unless defined? DEVELOPMENT
|
3
|
-
APP_NAME="rest-ftp-daemon"
|
4
|
-
|
5
|
-
class Settings < Settingslogic
|
6
|
-
namespace DEVELOPMENT ? "development" : "production"
|
7
|
-
suppress_errors namespace!="development"
|
8
|
-
end
|
9
|
-
|
10
|
-
# Fix application defaults and load config file if found
|
11
|
-
app_config_file = "/etc/#{APP_NAME}.yml"
|
12
|
-
if File.exists? app_config_file
|
13
|
-
Settings.source app_config_file
|
14
|
-
else
|
15
|
-
Settings.source Hash.new
|
16
|
-
end
|
17
|
-
|
18
|
-
# Forced shared settings
|
19
|
-
Settings[:name] = APP_NAME
|
20
|
-
Settings[:version] = 0.60
|
21
|
-
|
22
|
-
# Forced fixed settings
|
23
|
-
Settings[:default_trim_progname] = "18"
|
24
|
-
Settings[:default_chunk_size] = "1000000"
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module RestFtpDaemon
|
2
|
-
|
3
|
-
class RestFtpDaemonException < StandardError; end
|
4
|
-
|
5
|
-
class DummyException < RestFtpDaemonException; end
|
6
|
-
|
7
|
-
class RequestSourceMissing < RestFtpDaemonException; end
|
8
|
-
class RequestSourceNotFound < RestFtpDaemonException; end
|
9
|
-
class RequestTargetMissing < RestFtpDaemonException; end
|
10
|
-
class RequestTargetScheme < RestFtpDaemonException; end
|
11
|
-
|
12
|
-
class JobPrerequisitesNotMet < RestFtpDaemonException; end
|
13
|
-
|
14
|
-
class JobNotFound < RestFtpDaemonException; end
|
15
|
-
class JobSourceMissing < RestFtpDaemonException; end
|
16
|
-
class JobSourceNotFound < RestFtpDaemonException; end
|
17
|
-
class JobTargetMissing < RestFtpDaemonException; end
|
18
|
-
class JobTargetUnparseable < RestFtpDaemonException; end
|
19
|
-
#class JobTargetPermission < RestFtpDaemonException; end
|
20
|
-
class JobTargetFileExists < RestFtpDaemonException; end
|
21
|
-
|
22
|
-
class NotificationMissingUrl < RestFtpDaemonException; end
|
23
|
-
class NotificationMissingSignal < RestFtpDaemonException; end
|
24
|
-
|
25
|
-
|
26
|
-
end
|