rest-ftp-daemon 0.247.1 → 0.250.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 +6 -6
- data/README.md +1 -1
- data/config.ru +3 -0
- data/lib/rest-ftp-daemon.rb +6 -0
- data/lib/rest-ftp-daemon/api/config.rb +25 -0
- data/lib/rest-ftp-daemon/api/dashboard.rb +1 -12
- data/lib/rest-ftp-daemon/api/debug.rb +37 -0
- data/lib/rest-ftp-daemon/api/job_presenter.rb +0 -2
- data/lib/rest-ftp-daemon/api/jobs.rb +1 -26
- data/lib/rest-ftp-daemon/api/root.rb +32 -107
- data/lib/rest-ftp-daemon/api/status.rb +41 -0
- data/lib/rest-ftp-daemon/constants.rb +4 -1
- data/lib/rest-ftp-daemon/job.rb +10 -5
- data/lib/rest-ftp-daemon/job_queue.rb +81 -60
- data/lib/rest-ftp-daemon/notification.rb +9 -2
- data/lib/rest-ftp-daemon/stats.rb +42 -0
- data/lib/rest-ftp-daemon/views/dashboard.haml +3 -2
- data/lib/rest-ftp-daemon/views/dashboard_footer.haml +0 -1
- data/lib/rest-ftp-daemon/views/dashboard_header.haml +3 -3
- data/lib/rest-ftp-daemon/views/dashboard_jobs.haml +6 -6
- data/lib/rest-ftp-daemon/views/dashboard_rates.haml +36 -0
- data/lib/rest-ftp-daemon/views/dashboard_stats.haml +21 -0
- data/lib/rest-ftp-daemon/views/dashboard_table.haml +0 -8
- data/lib/rest-ftp-daemon/views/dashboard_tokens.haml +9 -7
- data/lib/rest-ftp-daemon/views/dashboard_workers.haml +27 -25
- data/lib/rest-ftp-daemon/worker_job.rb +1 -1
- data/rest-ftp-daemon.gemspec +1 -1
- data/spec/rest-ftp-daemon/features/{routes_spec.rb → debug_spec.rb} +3 -3
- data/spec/rest-ftp-daemon/features/status_spec.rb +2 -2
- metadata +11 -6
- data/lib/rest-ftp-daemon/views/dashboard_counters.haml +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56ef0db0f52451ad8dd48acea697310637a460a7
|
4
|
+
data.tar.gz: 8c1c45f0077e055a48c6d80bb1d9f60892019d2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d8120b207886ab8a2667b68761e539a23cc547d04880844d0898ac6560a2edeea313033dca26de45b6af51f0715a97a3e7ad82e626b3915f2255d530ab0dadee
|
7
|
+
data.tar.gz: 43e8dff779837f56751a1accb9ddf69fe122cc31af4ec97c83ce556028b27199164bb9bc9b7aebe708b1a108e060a3fbb8a8752aae33d21f90eb137ab33d0378
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rest-ftp-daemon (0.
|
4
|
+
rest-ftp-daemon (0.250.0)
|
5
5
|
double-bag-ftps
|
6
6
|
facter
|
7
7
|
get_process_mem
|
@@ -13,7 +13,7 @@ PATH
|
|
13
13
|
newrelic_rpm
|
14
14
|
settingslogic
|
15
15
|
sys-cpu
|
16
|
-
thin (~> 1.6)
|
16
|
+
thin (~> 1.6.4)
|
17
17
|
|
18
18
|
GEM
|
19
19
|
remote: http://rubygems.org/
|
@@ -80,8 +80,8 @@ GEM
|
|
80
80
|
ice_nine (0.11.2)
|
81
81
|
json (1.8.3)
|
82
82
|
method_source (0.8.2)
|
83
|
-
minitest (5.
|
84
|
-
multi_json (1.12.
|
83
|
+
minitest (5.9.0)
|
84
|
+
multi_json (1.12.1)
|
85
85
|
multi_xml (0.5.5)
|
86
86
|
mustermann19 (0.4.3)
|
87
87
|
enumerable-lazy
|
@@ -120,7 +120,7 @@ GEM
|
|
120
120
|
powerpack (~> 0.1)
|
121
121
|
rainbow (>= 1.99.1, < 3.0)
|
122
122
|
ruby-progressbar (~> 1.4)
|
123
|
-
ruby-progressbar (1.8.
|
123
|
+
ruby-progressbar (1.8.1)
|
124
124
|
settingslogic (2.0.9)
|
125
125
|
slop (3.6.0)
|
126
126
|
sys-cpu (0.7.2)
|
@@ -130,7 +130,7 @@ GEM
|
|
130
130
|
eventmachine (~> 1.0, >= 1.0.4)
|
131
131
|
rack (~> 1.0)
|
132
132
|
thread_safe (0.3.5)
|
133
|
-
tilt (2.0.
|
133
|
+
tilt (2.0.4)
|
134
134
|
tzinfo (1.2.2)
|
135
135
|
thread_safe (~> 0.1)
|
136
136
|
unf (0.1.4)
|
data/README.md
CHANGED
data/config.ru
CHANGED
data/lib/rest-ftp-daemon.rb
CHANGED
@@ -10,6 +10,8 @@ require "net/http"
|
|
10
10
|
require "thread"
|
11
11
|
require "singleton"
|
12
12
|
require "newrelic_rpm"
|
13
|
+
require "grape"
|
14
|
+
require "grape-entity"
|
13
15
|
|
14
16
|
# Project's libs
|
15
17
|
require_relative "rest-ftp-daemon/constants"
|
@@ -23,6 +25,7 @@ require_relative "rest-ftp-daemon/logger"
|
|
23
25
|
require_relative "rest-ftp-daemon/paginate"
|
24
26
|
require_relative "rest-ftp-daemon/uri"
|
25
27
|
require_relative "rest-ftp-daemon/job_queue"
|
28
|
+
require_relative "rest-ftp-daemon/stats"
|
26
29
|
require_relative "rest-ftp-daemon/worker"
|
27
30
|
require_relative "rest-ftp-daemon/worker_conchita"
|
28
31
|
require_relative "rest-ftp-daemon/worker_job"
|
@@ -38,6 +41,9 @@ require_relative "rest-ftp-daemon/remote_sftp"
|
|
38
41
|
require_relative "rest-ftp-daemon/api/job_presenter"
|
39
42
|
require_relative "rest-ftp-daemon/api/jobs"
|
40
43
|
require_relative "rest-ftp-daemon/api/dashboard"
|
44
|
+
require_relative "rest-ftp-daemon/api/status"
|
45
|
+
require_relative "rest-ftp-daemon/api/config"
|
46
|
+
require_relative "rest-ftp-daemon/api/debug"
|
41
47
|
require_relative "rest-ftp-daemon/api/root"
|
42
48
|
|
43
49
|
# Haml monkey-patching
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RestFtpDaemon
|
2
|
+
module API
|
3
|
+
class Config < Grape::API
|
4
|
+
|
5
|
+
desc "Show daemon config"
|
6
|
+
get "/" do
|
7
|
+
status 200
|
8
|
+
return Helpers.get_censored_config
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Reload daemon config"
|
12
|
+
post "/reload" do
|
13
|
+
if Settings.at(:debug, :allow_reload)==true
|
14
|
+
Settings.reload!
|
15
|
+
status 200
|
16
|
+
return Helpers.get_censored_config
|
17
|
+
else
|
18
|
+
status 403
|
19
|
+
return "Config reload not permitted"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,21 +1,16 @@
|
|
1
|
-
require "grape"
|
2
1
|
require "haml"
|
3
2
|
require "sys/cpu"
|
3
|
+
require "get_process_mem"
|
4
4
|
require "facter"
|
5
5
|
|
6
6
|
module RestFtpDaemon
|
7
7
|
module API
|
8
8
|
|
9
|
-
# Offers an HTML dashboard through the Grape API (hum...)
|
10
9
|
class Dashbaord < Grape::API
|
11
10
|
|
12
11
|
### HELPERS
|
13
12
|
|
14
13
|
helpers do
|
15
|
-
def logger
|
16
|
-
Root.logger
|
17
|
-
end
|
18
|
-
|
19
14
|
def render name, values={}
|
20
15
|
template = File.read("#{APP_LIBS}/views/#{name}.haml")
|
21
16
|
|
@@ -65,12 +60,6 @@ module RestFtpDaemon
|
|
65
60
|
end
|
66
61
|
|
67
62
|
|
68
|
-
### Common request logging
|
69
|
-
before do
|
70
|
-
log_info "HTTP #{request.request_method} #{request.fullpath}", params
|
71
|
-
end
|
72
|
-
|
73
|
-
|
74
63
|
### DASHBOARD
|
75
64
|
desc "Show a global dashboard"
|
76
65
|
get "/" do
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RestFtpDaemon
|
2
|
+
module API
|
3
|
+
class Debug < Grape::API
|
4
|
+
|
5
|
+
desc "Show app routes, params encodings"
|
6
|
+
get "/" do
|
7
|
+
# Encodings
|
8
|
+
encodings = {}
|
9
|
+
jobs = $queue.jobs
|
10
|
+
|
11
|
+
jobs.each do |job|
|
12
|
+
# here = out[job.id] = {}
|
13
|
+
me = encodings[job.id] = {}
|
14
|
+
|
15
|
+
me[:error] = job.error.encoding.to_s unless job.error.nil?
|
16
|
+
me[:status] = job.status.encoding.to_s unless job.status.nil?
|
17
|
+
|
18
|
+
Job::FIELDS.each do |name|
|
19
|
+
value = job.send(name)
|
20
|
+
me[name] = value.encoding.to_s if value.is_a? String
|
21
|
+
end
|
22
|
+
|
23
|
+
job.infos.each do |name, value|
|
24
|
+
me["infos_#{name}"] = value.encoding.to_s if value.is_a? String
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Build response
|
29
|
+
return {
|
30
|
+
routes: RestFtpDaemon::API::Root.routes,
|
31
|
+
encodings: encodings,
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,26 +1,7 @@
|
|
1
|
-
require "grape"
|
2
|
-
|
3
1
|
module RestFtpDaemon
|
4
2
|
module API
|
5
3
|
class Jobs < Grape::API
|
6
4
|
|
7
|
-
### HELPERS
|
8
|
-
|
9
|
-
helpers do
|
10
|
-
def logger
|
11
|
-
Root.logger
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
### Common request logging
|
17
|
-
before do
|
18
|
-
log_info "HTTP #{request.request_method} #{request.fullpath}", params
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
### READ ONE JOB
|
23
|
-
|
24
5
|
desc "Read job with ID"
|
25
6
|
params do
|
26
7
|
requires :id, type: String, desc: "ID of the Job to read"
|
@@ -47,9 +28,6 @@ module RestFtpDaemon
|
|
47
28
|
end
|
48
29
|
end
|
49
30
|
|
50
|
-
|
51
|
-
### READ ALL JOBS
|
52
|
-
|
53
31
|
desc "List all Jobs"
|
54
32
|
get "/" do
|
55
33
|
begin
|
@@ -67,9 +45,6 @@ module RestFtpDaemon
|
|
67
45
|
end
|
68
46
|
end
|
69
47
|
|
70
|
-
|
71
|
-
### CREATE A JOB
|
72
|
-
|
73
48
|
desc "Create a new job"
|
74
49
|
params do
|
75
50
|
requires :source, type: String, desc: "Source file pattern"
|
@@ -102,7 +77,7 @@ module RestFtpDaemon
|
|
102
77
|
$queue.push job
|
103
78
|
|
104
79
|
# Increment a counter
|
105
|
-
$
|
80
|
+
$stats.increment :jobs, :received
|
106
81
|
|
107
82
|
rescue JSON::ParserError => exception
|
108
83
|
log_error "JSON::ParserError: #{exception.message}"
|
@@ -1,23 +1,50 @@
|
|
1
|
-
require "grape"
|
2
|
-
require "get_process_mem"
|
3
|
-
|
4
1
|
module RestFtpDaemon
|
5
2
|
module API
|
6
3
|
class Root < Grape::API
|
7
4
|
|
5
|
+
### LOGGING & HELPERS
|
6
|
+
|
7
|
+
helpers do
|
8
|
+
def logger
|
9
|
+
Root.logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def log_request
|
13
|
+
if env.nil?
|
14
|
+
puts "HTTP_ENV_IS_NIL: #{env.inspect}"
|
15
|
+
return
|
16
|
+
end
|
17
|
+
|
18
|
+
request_method = env['REQUEST_METHOD']
|
19
|
+
request_path = env['REQUEST_PATH']
|
20
|
+
request_uri = env['REQUEST_URI']
|
21
|
+
log_info "HTTP #{request_method} #{request_uri}", params
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
before do
|
26
|
+
log_request
|
27
|
+
end
|
28
|
+
|
29
|
+
|
8
30
|
### CLASS CONFIG
|
9
31
|
|
10
32
|
helpers RestFtpDaemon::LoggerHelper
|
11
33
|
logger RestFtpDaemon::LoggerPool.instance.get :api
|
12
|
-
|
13
34
|
do_not_route_head!
|
14
35
|
do_not_route_options!
|
15
|
-
|
36
|
+
# version 'v1'
|
16
37
|
format :json
|
17
38
|
content_type :json, 'application/json; charset=utf-8'
|
18
39
|
|
40
|
+
|
41
|
+
### MOUNTPOINTS
|
42
|
+
|
43
|
+
mount RestFtpDaemon::API::Status => MOUNT_STATUS
|
19
44
|
mount RestFtpDaemon::API::Jobs => MOUNT_JOBS
|
20
45
|
mount RestFtpDaemon::API::Dashbaord => MOUNT_BOARD
|
46
|
+
mount RestFtpDaemon::API::Config => MOUNT_CONFIG
|
47
|
+
mount RestFtpDaemon::API::Debug => MOUNT_DEBUG
|
21
48
|
|
22
49
|
|
23
50
|
### INITIALIZATION
|
@@ -32,114 +59,12 @@ module RestFtpDaemon
|
|
32
59
|
end
|
33
60
|
|
34
61
|
|
35
|
-
### HELPERS
|
36
|
-
|
37
|
-
helpers do
|
38
|
-
def logger
|
39
|
-
Root.logger
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
### Common request logging
|
45
|
-
|
46
|
-
before do
|
47
|
-
log_info "HTTP #{request.request_method} #{request.fullpath}", params
|
48
|
-
end
|
49
|
-
|
50
|
-
|
51
62
|
### ROOT URL ACCESS
|
52
63
|
|
53
64
|
get "/" do
|
54
65
|
redirect Helpers.dashboard_filter_url()
|
55
66
|
end
|
56
67
|
|
57
|
-
|
58
|
-
### SHOW ROUTES
|
59
|
-
|
60
|
-
desc "Show application routes"
|
61
|
-
get "/routes" do
|
62
|
-
status 200
|
63
|
-
return RestFtpDaemon::API::Root.routes
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
### SHOW STATUS
|
68
|
-
|
69
|
-
desc "Show daemon status"
|
70
|
-
get "/status" do
|
71
|
-
mem = GetProcessMem.new
|
72
|
-
status 200
|
73
|
-
return {
|
74
|
-
hostname: `hostname`.to_s.chomp,
|
75
|
-
version: APP_VER,
|
76
|
-
started: APP_STARTED,
|
77
|
-
uptime: (Time.now - APP_STARTED).round(1),
|
78
|
-
counters: $queue.counters,
|
79
|
-
memory_bytes: mem.bytes.to_i,
|
80
|
-
memory_mb: mem.mb.round(0),
|
81
|
-
status: $queue.counts_by_status,
|
82
|
-
workers: $pool.worker_variables,
|
83
|
-
jobs_count: $queue.jobs_count,
|
84
|
-
jobs_queued: $queue.queued_ids,
|
85
|
-
}
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
### SHOW CONFIG
|
90
|
-
|
91
|
-
desc "Show daemon config"
|
92
|
-
get "/config" do
|
93
|
-
status 200
|
94
|
-
return Helpers.get_censored_config
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
desc "List all Jobs params encodings"
|
99
|
-
get "/encodings" do
|
100
|
-
# Get jobs to display
|
101
|
-
encodings = {}
|
102
|
-
jobs = $queue.jobs
|
103
|
-
|
104
|
-
jobs.each do |job|
|
105
|
-
# here = out[job.id] = {}
|
106
|
-
me = encodings[job.id] = {}
|
107
|
-
|
108
|
-
me[:error] = job.error.encoding.to_s unless job.error.nil?
|
109
|
-
me[:status] = job.status.encoding.to_s unless job.status.nil?
|
110
|
-
|
111
|
-
Job::FIELDS.each do |name|
|
112
|
-
value = job.send(name)
|
113
|
-
me[name] = value.encoding.to_s if value.is_a? String
|
114
|
-
end
|
115
|
-
|
116
|
-
job.infos.each do |name, value|
|
117
|
-
me["infos_#{name}"] = value.encoding.to_s if value.is_a? String
|
118
|
-
end
|
119
|
-
|
120
|
-
# # Computed fields
|
121
|
-
# expose :age
|
122
|
-
# expose :exectime
|
123
|
-
end
|
124
|
-
|
125
|
-
encodings
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
### RELOAD CONFIG
|
130
|
-
|
131
|
-
desc "Reload daemon config"
|
132
|
-
post "/config/reload" do
|
133
|
-
if Settings.at(:debug, :allow_reload)==true
|
134
|
-
Settings.reload!
|
135
|
-
status 200
|
136
|
-
return Helpers.get_censored_config
|
137
|
-
else
|
138
|
-
status 403
|
139
|
-
return "Config reload not permitted"
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
68
|
end
|
144
69
|
end
|
145
70
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "get_process_mem"
|
2
|
+
|
3
|
+
module RestFtpDaemon
|
4
|
+
module API
|
5
|
+
class Status < Grape::API
|
6
|
+
|
7
|
+
desc "Show daemon status"
|
8
|
+
get "/" do
|
9
|
+
mem = GetProcessMem.new
|
10
|
+
status 200
|
11
|
+
return {
|
12
|
+
hostname: `hostname`.to_s.chomp,
|
13
|
+
version: APP_VER,
|
14
|
+
|
15
|
+
started: APP_STARTED,
|
16
|
+
uptime: (Time.now - APP_STARTED).round(1),
|
17
|
+
|
18
|
+
memory_bytes: mem.bytes.to_i,
|
19
|
+
memory_mb: mem.mb.round(0),
|
20
|
+
|
21
|
+
stats: $stats.stats,
|
22
|
+
|
23
|
+
jobs_count: $queue.jobs_count,
|
24
|
+
status: $queue.jobs_count_by_status,
|
25
|
+
|
26
|
+
# jobs_finished: $queue.jobs_finished,
|
27
|
+
#rate_by_pool1: $queue.rate_by_pool,
|
28
|
+
rate_by_pool: $queue.rate_by(:pool),
|
29
|
+
rate_by_targethost: $queue.rate_by(:targethost),
|
30
|
+
jobs_by_status: $queue.jobs_by_status,
|
31
|
+
|
32
|
+
#rates_per_host: $queue.rates_per_host,
|
33
|
+
|
34
|
+
workers: $pool.worker_variables,
|
35
|
+
#kpis: $queue.queued_ids,
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Terrific constants
|
2
2
|
APP_NAME = "rest-ftp-daemon"
|
3
3
|
APP_NICK = "rftpd"
|
4
|
-
APP_VER = "0.
|
4
|
+
APP_VER = "0.250.0"
|
5
5
|
|
6
6
|
# Provide default config file information
|
7
7
|
APP_LIB = File.expand_path(File.dirname(__FILE__))
|
@@ -92,6 +92,9 @@ BIND_PORT_LOCALHOST = "127.0.0.1"
|
|
92
92
|
ENV_PRODUCTION = "production"
|
93
93
|
MOUNT_JOBS = "/jobs"
|
94
94
|
MOUNT_BOARD = "/board"
|
95
|
+
MOUNT_STATUS = "/status"
|
96
|
+
MOUNT_DEBUG = "/debug"
|
97
|
+
MOUNT_CONFIG = "/config"
|
95
98
|
|
96
99
|
|
97
100
|
# Notifications
|
data/lib/rest-ftp-daemon/job.rb
CHANGED
@@ -246,6 +246,10 @@ module RestFtpDaemon
|
|
246
246
|
(Time.now - @queued_at).round(2)
|
247
247
|
end
|
248
248
|
|
249
|
+
def targethost
|
250
|
+
get(:target_host)
|
251
|
+
end
|
252
|
+
|
249
253
|
def json_target
|
250
254
|
utf8 @target_method
|
251
255
|
end
|
@@ -314,6 +318,7 @@ module RestFtpDaemon
|
|
314
318
|
raise RestFtpDaemon::JobMissingAttribute unless @target
|
315
319
|
target_uri = expand_url @target
|
316
320
|
set_info :target_uri, target_uri.to_s
|
321
|
+
set_info :target_host, target_uri.host
|
317
322
|
@target_path = Path.new target_uri.path, true
|
318
323
|
|
319
324
|
#puts "@target_path: #{@target_path.inspect}"
|
@@ -485,9 +490,9 @@ module RestFtpDaemon
|
|
485
490
|
set_status JOB_STATUS_DISCONNECTING
|
486
491
|
@finished_at = Time.now
|
487
492
|
|
488
|
-
# Update
|
489
|
-
$
|
490
|
-
$
|
493
|
+
# Update stats
|
494
|
+
$stats.increment :jobs, :finished
|
495
|
+
$stats.add :global, :transferred, @transfer_total
|
491
496
|
end
|
492
497
|
|
493
498
|
def remote_push source, target
|
@@ -652,8 +657,8 @@ module RestFtpDaemon
|
|
652
657
|
end
|
653
658
|
|
654
659
|
# Increment counter for this error
|
655
|
-
$
|
656
|
-
$
|
660
|
+
$stats.increment :errors, error
|
661
|
+
$stats.increment :jobs, :failed
|
657
662
|
|
658
663
|
# Prepare notification if signal given
|
659
664
|
return unless event
|
@@ -35,10 +35,6 @@ module RestFtpDaemon
|
|
35
35
|
@last_id = 0
|
36
36
|
@prefix = Helpers.identifier JOB_IDENT_LEN
|
37
37
|
log_info "JobQueue initialized (prefix: #{@prefix})"
|
38
|
-
|
39
|
-
# Mutex for counters
|
40
|
-
@counters = {}
|
41
|
-
@mutex_counters = Mutex.new
|
42
38
|
end
|
43
39
|
|
44
40
|
def generate_id
|
@@ -48,63 +44,58 @@ module RestFtpDaemon
|
|
48
44
|
prefixed_id @last_id
|
49
45
|
end
|
50
46
|
|
51
|
-
|
52
|
-
@
|
53
|
-
|
54
|
-
@counters[name] += value
|
55
|
-
end
|
47
|
+
def jobs_queued
|
48
|
+
@queues
|
49
|
+
#@queues.map { |status, jobs| jobs.size }
|
56
50
|
end
|
57
51
|
|
58
|
-
|
59
|
-
|
60
|
-
|
52
|
+
# Statistics on average rates
|
53
|
+
def rate_by method_name
|
54
|
+
# Init
|
55
|
+
rates = {}
|
56
|
+
return unless Job.new(0, {}).respond_to? method_name
|
61
57
|
|
62
|
-
|
63
|
-
@
|
64
|
-
|
58
|
+
# Group jobs by method_name
|
59
|
+
jobs_grouped = @jobs.group_by do |job|
|
60
|
+
job.send(method_name)
|
65
61
|
end
|
66
|
-
end
|
67
62
|
|
68
|
-
|
69
|
-
|
70
|
-
|
63
|
+
# Inside each group, sum up rates for interesting statuses
|
64
|
+
jobs_grouped.map do |group, jobs|
|
65
|
+
# Store their sum
|
66
|
+
rates[group] = rates_by_status (jobs)
|
71
67
|
end
|
72
|
-
end
|
73
68
|
|
74
|
-
|
75
|
-
|
69
|
+
# Return the rate
|
70
|
+
rates
|
76
71
|
end
|
77
72
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
@jobs.reject { |job| job.status == JOB_STATUS_QUEUED }
|
82
|
-
|
83
|
-
# Status filtering: only those jobs
|
84
|
-
else
|
85
|
-
@jobs.select { |job| job.status.to_s == status.to_s }
|
86
|
-
|
87
|
-
end
|
73
|
+
# Queue infos
|
74
|
+
def jobs_count
|
75
|
+
@jobs.length
|
88
76
|
end
|
89
77
|
|
90
|
-
def
|
78
|
+
def jobs_by_status
|
91
79
|
statuses = {}
|
92
80
|
@jobs.group_by { |job| job.status }.map { |status, jobs| statuses[status] = jobs.size }
|
93
81
|
statuses
|
94
82
|
end
|
83
|
+
alias jobs_count_by_status jobs_by_status
|
95
84
|
|
96
|
-
def
|
97
|
-
@jobs.
|
85
|
+
def jobs_ids
|
86
|
+
@jobs.collect(&:id)
|
98
87
|
end
|
99
88
|
|
100
|
-
def
|
101
|
-
@
|
89
|
+
def empty?
|
90
|
+
@queue.empty?
|
102
91
|
end
|
103
92
|
|
104
|
-
def
|
105
|
-
@
|
93
|
+
def num_waiting
|
94
|
+
@waiting.size
|
106
95
|
end
|
107
96
|
|
97
|
+
|
98
|
+
# Queue access
|
108
99
|
def find_by_id id, prefixed = false
|
109
100
|
# Build a prefixed id if expected
|
110
101
|
id = prefixed_id(id) if prefixed
|
@@ -115,7 +106,6 @@ module RestFtpDaemon
|
|
115
106
|
@jobs.find { |item| item.id == id }
|
116
107
|
end
|
117
108
|
|
118
|
-
|
119
109
|
def push job
|
120
110
|
# Check that item responds to "priorty" method
|
121
111
|
raise "JobQueue.push: job should respond to priority method" unless job.respond_to? :priority
|
@@ -174,42 +164,52 @@ module RestFtpDaemon
|
|
174
164
|
alias shift pop
|
175
165
|
alias deq pop
|
176
166
|
|
177
|
-
def empty?
|
178
|
-
@queue.empty?
|
179
|
-
end
|
180
|
-
|
181
167
|
def clear
|
182
168
|
@queue.clear
|
183
169
|
end
|
184
170
|
|
185
|
-
|
186
|
-
|
171
|
+
# Jobs acess and searching
|
172
|
+
def jobs_with_status status
|
173
|
+
# No status filter: return all execept queued
|
174
|
+
if status.empty?
|
175
|
+
@jobs.reject { |job| job.status == JOB_STATUS_QUEUED }
|
176
|
+
|
177
|
+
# Status filtering: only those jobs
|
178
|
+
else
|
179
|
+
@jobs.select { |job| job.status.to_s == status.to_s }
|
180
|
+
|
181
|
+
end
|
187
182
|
end
|
188
183
|
|
184
|
+
# Jobs cleanup
|
189
185
|
def expire status, maxage, verbose = false
|
190
186
|
# FIXME: clean both @jobs and @queue
|
191
187
|
# Init
|
192
188
|
return if status.nil? || maxage <= 0
|
193
189
|
|
194
|
-
# Compute oldest
|
195
|
-
|
196
|
-
|
197
|
-
# Verbose output ?
|
198
|
-
log_info "JobQueue.expire \t[#{status}] \tbefore \t[#{before}]" if verbose
|
190
|
+
# Compute oldest limit
|
191
|
+
time_limit = Time.now - maxage.to_i
|
192
|
+
log_info "JobQueue.expire limit [#{time_limit}] status [#{status}]" if verbose
|
199
193
|
|
200
194
|
@mutex.synchronize do
|
201
195
|
# Delete jobs from the queue when they match status and age limits
|
202
196
|
@jobs.delete_if do |job|
|
197
|
+
# log_info "testing job [#{job.id}] updated_at [#{job.updated_at}]"
|
203
198
|
|
204
|
-
# Skip if wrong status, updated_at invalid, or
|
205
|
-
next unless job.status == status
|
199
|
+
# Skip if wrong status, updated_at invalid, or updated since time_limit
|
200
|
+
next unless job.status == status
|
206
201
|
next if job.updated_at.nil?
|
207
|
-
next if job.updated_at
|
202
|
+
next if job.updated_at >= time_limit
|
208
203
|
|
209
204
|
# Ok, we have to clean it up ..
|
210
|
-
log_info "expire [#{status}]
|
211
|
-
log_info "#{LOG_INDENT}unqueued" if @queue.delete(job)
|
205
|
+
log_info "expire [#{status}]: job [#{job.id}] updated_at [#{job.updated_at}]"
|
212
206
|
|
207
|
+
# From any queues, remove it
|
208
|
+
@queues.each do |pool, jobs|
|
209
|
+
log_info "#{LOG_INDENT}unqueued from [#{pool}]" if jobs.delete(job)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Remember we have to delete the original job !
|
213
213
|
true
|
214
214
|
end
|
215
215
|
end
|
@@ -222,11 +222,32 @@ module RestFtpDaemon
|
|
222
222
|
"#{@prefix}.#{id}"
|
223
223
|
end
|
224
224
|
|
225
|
+
def rates_by_status jobs
|
226
|
+
rates = {}
|
227
|
+
|
228
|
+
# Sub-group by status
|
229
|
+
jobs.group_by(&:status).each do |status, jobset|
|
230
|
+
|
231
|
+
# Extract bitrate values
|
232
|
+
bitrates = jobset.collect do |job|
|
233
|
+
job.get(:transfer_bitrate)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Store their sum
|
237
|
+
rates[status] = bitrates.reject(&:nil?).sum
|
238
|
+
# rates["#{status}_ids"] = jobset.collect(&:id).join(', ')
|
239
|
+
end
|
240
|
+
|
241
|
+
# Return rates
|
242
|
+
rates
|
243
|
+
end
|
244
|
+
|
225
245
|
if Settings.newrelic_enabled?
|
226
|
-
add_transaction_tracer :push,
|
227
|
-
add_transaction_tracer :pop,
|
228
|
-
add_transaction_tracer :expire,
|
229
|
-
add_transaction_tracer :
|
246
|
+
add_transaction_tracer :push, category: :task
|
247
|
+
add_transaction_tracer :pop, category: :task
|
248
|
+
add_transaction_tracer :expire, category: :task
|
249
|
+
add_transaction_tracer :rate_by, category: :task
|
250
|
+
add_transaction_tracer :jobs_count_by_status, category: :task
|
230
251
|
end
|
231
252
|
|
232
253
|
end
|
@@ -75,8 +75,9 @@ module RestFtpDaemon
|
|
75
75
|
# Post notification, handle server response / multi-lines
|
76
76
|
log_info "sending #{data}"
|
77
77
|
response = http.post uri.path, data, headers
|
78
|
-
response_lines = response.body.lines
|
79
78
|
|
79
|
+
# Log reponse body
|
80
|
+
response_lines = response.body.lines
|
80
81
|
if response_lines.size > 1
|
81
82
|
human_size = Helpers.format_bytes(response.body.bytesize, "B")
|
82
83
|
log_info "received [#{response.code}] #{human_size} (#{response_lines.size} lines)", response_lines
|
@@ -85,8 +86,14 @@ module RestFtpDaemon
|
|
85
86
|
end
|
86
87
|
|
87
88
|
# Handle exceptions
|
89
|
+
rescue Net::OpenTimeout => ex
|
90
|
+
log_error "Net::OpenTimeout: #{ex.inspect}"
|
91
|
+
|
92
|
+
rescue SocketError => ex
|
93
|
+
log_error "SocketError: #{ex.inspect}"
|
94
|
+
|
88
95
|
rescue StandardError => ex
|
89
|
-
log_error "
|
96
|
+
log_error "UNHANDLED EXCEPTION: #{ex.inspect}"
|
90
97
|
end
|
91
98
|
|
92
99
|
def log_context
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module RestFtpDaemon
|
2
|
+
|
3
|
+
# Queue that stores all the Jobs waiting to be processed or fully processed
|
4
|
+
class Stats
|
5
|
+
attr_reader :stats
|
6
|
+
|
7
|
+
if Settings.newrelic_enabled?
|
8
|
+
include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@stats = {}
|
13
|
+
@mutex_stats = Mutex.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def set group, name, value
|
17
|
+
@mutex_stats.synchronize do
|
18
|
+
@stats[group] ||= {}
|
19
|
+
@stats[group][name] = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def get group, name
|
24
|
+
@mutex_stats.synchronize do
|
25
|
+
@stats[group][name] if @stats[group]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def add group, name, value
|
30
|
+
@mutex_stats.synchronize do
|
31
|
+
@stats[group] ||= {}
|
32
|
+
@stats[group][name] ||= 0
|
33
|
+
@stats[group][name] += value
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def increment group, name
|
38
|
+
add group, name, 1
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
-# coding: utf-8
|
2
|
-
- trans = $queue.counter_get :transferred
|
3
2
|
- info_procs = (Facter.value :processorcount).to_i
|
4
3
|
- info_load = Sys::CPU.load_avg.first.to_f
|
5
4
|
- info_norm = info_procs.zero? ? "N/A" : (100 * info_load / info_procs).round(1)
|
6
|
-
-
|
5
|
+
- info_trans = $stats.get :global, :transferred
|
6
|
+
- info_processed = $stats.get(:global, :processed)
|
7
7
|
- mem = GetProcessMem.new
|
8
8
|
|
9
9
|
|
@@ -35,6 +35,6 @@
|
|
35
35
|
|
36
36
|
.btn-group.btn-group-sm
|
37
37
|
.btn.btn-default.btn-success Transferred
|
38
|
-
.btn.btn-default= Helpers.format_bytes(
|
38
|
+
.btn.btn-default= Helpers.format_bytes(info_trans, "B", 1)
|
39
39
|
|
40
40
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
-# coding: utf-8
|
2
|
-
-
|
2
|
+
- jobs_count_by_status = $queue.jobs_count_by_status
|
3
3
|
- counts_all = $queue.jobs_count
|
4
4
|
- jobs = @paginate.subset
|
5
5
|
|
@@ -9,7 +9,7 @@
|
|
9
9
|
ALL (#{counts_all})
|
10
10
|
|
11
11
|
.btn-group.btn-group-xs.filters
|
12
|
-
-
|
12
|
+
- jobs_count_by_status.each do |status, count|
|
13
13
|
- klass = (status.to_s == @filter) ? "btn-info" : ""
|
14
14
|
%a.btn.btn-default{href: Helpers.dashboard_filter_url(status), class: klass}
|
15
15
|
#{status} (#{count})
|
@@ -50,10 +50,10 @@
|
|
50
50
|
%tbody.jobs
|
51
51
|
= render :dashboard_table, {jobs: jobs}
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
%thead
|
54
|
+
%tr
|
55
|
+
%td{colspan: 14}
|
56
|
+
%br
|
57
57
|
|
58
58
|
- unless jobs.empty?
|
59
59
|
%tbody.jobs
|
@@ -0,0 +1,36 @@
|
|
1
|
+
-# coding: utf-8
|
2
|
+
|
3
|
+
- groups = {pool: "pool", targethost: "target host"}
|
4
|
+
|
5
|
+
|
6
|
+
%h2 Transfer rates
|
7
|
+
|
8
|
+
%table.table.table-striped.table-hover.table-condensed
|
9
|
+
|
10
|
+
- groups.each do |group_by, group_title|
|
11
|
+
- rates_by_status = $queue.rate_by(group_by)
|
12
|
+
|
13
|
+
%thead
|
14
|
+
%tr
|
15
|
+
%th= group_title
|
16
|
+
%th.text-right=JOB_STATUS_FINISHED
|
17
|
+
%th.text-right=JOB_STATUS_UPLOADING
|
18
|
+
|
19
|
+
%tbody
|
20
|
+
- rates_by_status.each do |group, rates|
|
21
|
+
- next if group.nil?
|
22
|
+
|
23
|
+
%tr.info
|
24
|
+
%td= group
|
25
|
+
%td.text-right
|
26
|
+
= Helpers.format_bytes(rates[JOB_STATUS_FINISHED], "bps")
|
27
|
+
%td.text-right
|
28
|
+
= Helpers.format_bytes(rates[JOB_STATUS_UPLOADING], "bps")
|
29
|
+
-# %td= rates.inspect
|
30
|
+
|
31
|
+
%thead
|
32
|
+
%tr
|
33
|
+
%td{colspan: 3}
|
34
|
+
%br
|
35
|
+
|
36
|
+
-# JOB_STATUS_UPLOADING
|
@@ -0,0 +1,21 @@
|
|
1
|
+
-# coding: utf-8
|
2
|
+
%h2 Stats
|
3
|
+
|
4
|
+
%table.table.table-striped.table-hover.table-condensed
|
5
|
+
|
6
|
+
%thead
|
7
|
+
%tr
|
8
|
+
%th group
|
9
|
+
%th name
|
10
|
+
%th.text-right value
|
11
|
+
|
12
|
+
%tbody
|
13
|
+
|
14
|
+
- $stats.stats.each do |group, values|
|
15
|
+
|
16
|
+
- values.each do |name, value|
|
17
|
+
%tr
|
18
|
+
%td= group
|
19
|
+
%td= name
|
20
|
+
%td.text-right= value
|
21
|
+
|
@@ -77,14 +77,6 @@
|
|
77
77
|
.label.label-default.flag.worker-label= job.priority
|
78
78
|
|
79
79
|
%td
|
80
|
-
|
81
80
|
.label.flag.worker-label{class: Helpers.job_runs_style(runs)}= runs
|
82
81
|
|
83
|
-
-#%td
|
84
|
-
- unless job.priority.nil?
|
85
|
-
.label.label-default.flag.worker-label= job.priority
|
86
|
-
|
87
|
-
- unless job.wid.nil?
|
88
|
-
.label.label-warning.flag.worker-label= job.wid
|
89
|
-
|
90
82
|
|
@@ -3,11 +3,13 @@
|
|
3
3
|
|
4
4
|
%table.table.table-striped.table-hover.table-condensed
|
5
5
|
|
6
|
-
%
|
7
|
-
%th token
|
8
|
-
%th value
|
9
|
-
|
10
|
-
- tokens.each do |token, value|
|
6
|
+
%thead
|
11
7
|
%tr
|
12
|
-
%
|
13
|
-
%
|
8
|
+
%th token
|
9
|
+
%th value
|
10
|
+
|
11
|
+
%tbody
|
12
|
+
- tokens.each do |token, value|
|
13
|
+
%tr
|
14
|
+
%td= Helpers.tokenize token
|
15
|
+
%td= Helpers.hide_credentials_from_url value
|
@@ -3,33 +3,35 @@
|
|
3
3
|
|
4
4
|
%table.table.table-striped.table-hover.table-condensed
|
5
5
|
|
6
|
-
%
|
7
|
-
%
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
%thead
|
7
|
+
%tr
|
8
|
+
%th pool
|
9
|
+
%th worker
|
10
|
+
%th status
|
11
|
+
%th job
|
12
|
+
%th.text-right seen
|
12
13
|
|
13
|
-
|
14
|
-
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
%tbody
|
15
|
+
- @worker_variables.each do |vars|
|
16
|
+
- wid = vars[:wid]
|
17
|
+
- status = vars[:status]
|
18
|
+
- alive = $pool.worker_alive? wid
|
19
|
+
- trclass = WORKER_STYLES[status]
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
- unless alive
|
22
|
+
- trclass = "danger"
|
23
|
+
- status = "DEAD"
|
22
24
|
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
%tr{class: trclass.to_s}
|
27
|
+
%td= vars[:pool]
|
28
|
+
%td= wid
|
29
|
+
%td= status
|
30
|
+
%td= vars[:jid]
|
31
|
+
%td.text-right
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
- if vars[:updated_at].is_a? Time
|
34
|
+
- no_news_for = (Time.now - vars[:updated_at]).round(0)
|
35
|
+
= Helpers.formatted_duration no_news_for
|
36
|
+
- else
|
37
|
+
= "?"
|
@@ -86,7 +86,7 @@ module RestFtpDaemon
|
|
86
86
|
worker_status WORKER_STATUS_FINISHED, job
|
87
87
|
|
88
88
|
# Increment total processed jobs count
|
89
|
-
$
|
89
|
+
$stats.increment :global, :processed
|
90
90
|
|
91
91
|
rescue RestFtpDaemon::JobTimeout => ex
|
92
92
|
log_error "JOB TIMED OUT", ex.backtrace
|
data/rest-ftp-daemon.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency "rubocop", "~> 0.32.0"
|
32
32
|
spec.add_development_dependency "pry"
|
33
33
|
|
34
|
-
spec.add_runtime_dependency "thin", "~> 1.6"
|
34
|
+
spec.add_runtime_dependency "thin", "~> 1.6.4"
|
35
35
|
spec.add_runtime_dependency "grape"
|
36
36
|
spec.add_runtime_dependency "grape-entity"
|
37
37
|
spec.add_runtime_dependency "settingslogic"
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe "
|
3
|
+
describe "Debug", feature: true do
|
4
4
|
|
5
|
-
let!(:response) { get
|
5
|
+
let!(:response) { get MOUNT_DEBUG }
|
6
6
|
|
7
|
-
describe "GET
|
7
|
+
describe "GET #{MOUNT_DEBUG}" do
|
8
8
|
|
9
9
|
it "responds successfully" do
|
10
10
|
expect(response.status).to eq 200
|
@@ -2,9 +2,9 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Status", feature: true do
|
4
4
|
|
5
|
-
let!(:response) { get
|
5
|
+
let!(:response) { get MOUNT_STATUS }
|
6
6
|
|
7
|
-
describe "GET
|
7
|
+
describe "GET #{MOUNT_DEBUG}" do
|
8
8
|
|
9
9
|
it "responds successfully" do
|
10
10
|
expect(response.status).to eq 200
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-ftp-daemon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.250.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bruno MEDICI
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 1.6.4
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 1.6.4
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: grape
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -282,10 +282,13 @@ files:
|
|
282
282
|
- bin/rest-ftp-daemon
|
283
283
|
- config.ru
|
284
284
|
- lib/rest-ftp-daemon.rb
|
285
|
+
- lib/rest-ftp-daemon/api/config.rb
|
285
286
|
- lib/rest-ftp-daemon/api/dashboard.rb
|
287
|
+
- lib/rest-ftp-daemon/api/debug.rb
|
286
288
|
- lib/rest-ftp-daemon/api/job_presenter.rb
|
287
289
|
- lib/rest-ftp-daemon/api/jobs.rb
|
288
290
|
- lib/rest-ftp-daemon/api/root.rb
|
291
|
+
- lib/rest-ftp-daemon/api/status.rb
|
289
292
|
- lib/rest-ftp-daemon/array.rb
|
290
293
|
- lib/rest-ftp-daemon/constants.rb
|
291
294
|
- lib/rest-ftp-daemon/exceptions.rb
|
@@ -305,12 +308,14 @@ files:
|
|
305
308
|
- lib/rest-ftp-daemon/settings.rb
|
306
309
|
- lib/rest-ftp-daemon/static/css/bootstrap.css
|
307
310
|
- lib/rest-ftp-daemon/static/css/main.css
|
311
|
+
- lib/rest-ftp-daemon/stats.rb
|
308
312
|
- lib/rest-ftp-daemon/uri.rb
|
309
313
|
- lib/rest-ftp-daemon/views/dashboard.haml
|
310
|
-
- lib/rest-ftp-daemon/views/dashboard_counters.haml
|
311
314
|
- lib/rest-ftp-daemon/views/dashboard_footer.haml
|
312
315
|
- lib/rest-ftp-daemon/views/dashboard_header.haml
|
313
316
|
- lib/rest-ftp-daemon/views/dashboard_jobs.haml
|
317
|
+
- lib/rest-ftp-daemon/views/dashboard_rates.haml
|
318
|
+
- lib/rest-ftp-daemon/views/dashboard_stats.haml
|
314
319
|
- lib/rest-ftp-daemon/views/dashboard_table.haml
|
315
320
|
- lib/rest-ftp-daemon/views/dashboard_tokens.haml
|
316
321
|
- lib/rest-ftp-daemon/views/dashboard_workers.haml
|
@@ -321,8 +326,8 @@ files:
|
|
321
326
|
- rest-ftp-daemon.gemspec
|
322
327
|
- rest-ftp-daemon.yml.sample
|
323
328
|
- spec/rest-ftp-daemon/features/dashboard_spec.rb
|
329
|
+
- spec/rest-ftp-daemon/features/debug_spec.rb
|
324
330
|
- spec/rest-ftp-daemon/features/jobs_spec.rb
|
325
|
-
- spec/rest-ftp-daemon/features/routes_spec.rb
|
326
331
|
- spec/rest-ftp-daemon/features/status_spec.rb
|
327
332
|
- spec/spec_helper.rb
|
328
333
|
- spec/support/config.yml
|