rest-ftp-daemon 0.245.1 → 0.246.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 +8 -8
- data/README.md +30 -22
- data/bin/rest-ftp-daemon +6 -8
- data/config.ru +2 -2
- data/lib/rest-ftp-daemon.rb +0 -7
- data/lib/rest-ftp-daemon/api/dashboard.rb +47 -35
- data/lib/rest-ftp-daemon/api/root.rb +9 -2
- data/lib/rest-ftp-daemon/constants.rb +21 -19
- data/lib/rest-ftp-daemon/helpers.rb +6 -2
- data/lib/rest-ftp-daemon/job_queue.rb +1 -1
- data/lib/rest-ftp-daemon/paginate.rb +6 -4
- data/lib/rest-ftp-daemon/views/dashboard_jobs.haml +4 -4
- data/lib/rest-ftp-daemon/views/dashboard_table.haml +2 -2
- data/lib/rest-ftp-daemon/views/dashboard_workers.haml +3 -3
- data/lib/rest-ftp-daemon/worker.rb +2 -2
- data/rest-ftp-daemon.gemspec +2 -2
- data/spec/rest-ftp-daemon/features/dashboard_spec.rb +3 -3
- data/spec/rest-ftp-daemon/features/jobs_spec.rb +23 -11
- data/spec/spec_helper.rb +3 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b2dbcef0066dfcba34977015d1ac5f6ffba2a49
|
4
|
+
data.tar.gz: 28a9f886e9b2fd3d1553ad81e7bad7a5057e8ed7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da64e4991cca801aaa527b85acfb33e87010cb289d0ce6d01553fcfb18239fb8c0e57e5a7bd659a088230cb6a21a120c4299e824fc16ac53d1bf01846ed96075
|
7
|
+
data.tar.gz: a46a0b53ed9ac39c5f287010214fa5cb4a684a377dd3332a8bbbad5f6db40becae3a87ac3065a30f8afe01187ae375b9d59858cabf41f4759cce41396f01ba0e
|
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.246.0)
|
5
5
|
double-bag-ftps
|
6
6
|
facter
|
7
7
|
get_process_mem
|
@@ -19,7 +19,7 @@ GEM
|
|
19
19
|
remote: http://rubygems.org/
|
20
20
|
specs:
|
21
21
|
CFPropertyList (2.2.8)
|
22
|
-
activesupport (4.2.5)
|
22
|
+
activesupport (4.2.5.1)
|
23
23
|
i18n (~> 0.7)
|
24
24
|
json (~> 1.7, >= 1.7.7)
|
25
25
|
minitest (~> 5.1)
|
@@ -46,7 +46,7 @@ GEM
|
|
46
46
|
double-bag-ftps (0.1.2)
|
47
47
|
equalizer (0.0.11)
|
48
48
|
eventmachine (1.0.9.1)
|
49
|
-
facter (2.4.
|
49
|
+
facter (2.4.6)
|
50
50
|
CFPropertyList (~> 2.2.6)
|
51
51
|
ffi (1.9.10)
|
52
52
|
get_process_mem (0.2.0)
|
@@ -79,14 +79,14 @@ GEM
|
|
79
79
|
ice_nine (0.11.1)
|
80
80
|
json (1.8.3)
|
81
81
|
method_source (0.8.2)
|
82
|
-
minitest (5.8.
|
82
|
+
minitest (5.8.4)
|
83
83
|
multi_json (1.11.2)
|
84
84
|
multi_xml (0.5.5)
|
85
85
|
net-sftp (2.1.2)
|
86
86
|
net-ssh (>= 2.6.5)
|
87
87
|
net-ssh (3.0.2)
|
88
|
-
newrelic_rpm (3.14.
|
89
|
-
parser (2.3.0.
|
88
|
+
newrelic_rpm (3.14.2.312)
|
89
|
+
parser (2.3.0.2)
|
90
90
|
ast (~> 2.2)
|
91
91
|
powerpack (0.1.1)
|
92
92
|
pry (0.10.3)
|
@@ -98,13 +98,13 @@ GEM
|
|
98
98
|
rack (>= 0.4)
|
99
99
|
rack-mount (0.8.3)
|
100
100
|
rack (>= 1.0.0)
|
101
|
-
rainbow (2.
|
101
|
+
rainbow (2.1.0)
|
102
102
|
rake (10.5.0)
|
103
103
|
rspec (3.4.0)
|
104
104
|
rspec-core (~> 3.4.0)
|
105
105
|
rspec-expectations (~> 3.4.0)
|
106
106
|
rspec-mocks (~> 3.4.0)
|
107
|
-
rspec-core (3.4.
|
107
|
+
rspec-core (3.4.2)
|
108
108
|
rspec-support (~> 3.4.0)
|
109
109
|
rspec-expectations (3.4.0)
|
110
110
|
diff-lcs (>= 1.2.0, < 2.0)
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ Features
|
|
21
21
|
* environment-aware configuration in a YAML file
|
22
22
|
* daemon process is tagged with its name and environment in process lists
|
23
23
|
* global dashboard directly served within the daemon HTTP interface
|
24
|
-
* support pooling of worker to
|
24
|
+
* support pooling of worker to dedicate workers to groups of jobs
|
25
25
|
|
26
26
|
* File management ans transferts
|
27
27
|
* allow authentication in FTP target in a standard URI-format
|
@@ -46,23 +46,21 @@ Status
|
|
46
46
|
------------------------------------------------------------------------------------
|
47
47
|
|
48
48
|
Though it may need more robust tests, this gem has been used successfully in production for
|
49
|
-
a while without glitches at France Télévisions.
|
49
|
+
a while without any glitches at France Télévisions.
|
50
50
|
|
51
51
|
Expected features in a short-time range :
|
52
52
|
|
53
53
|
* Provide swagger-style API documentation
|
54
54
|
* Authenticate API clients
|
55
|
-
* Allow more transfer protocols (
|
55
|
+
* Allow more transfer protocols (HTTP POST etc)
|
56
56
|
* Expose JSON status of workers on `GET /jobs/` for automated monitoring
|
57
57
|
|
58
58
|
|
59
59
|
|
60
|
-
|
61
60
|
Installation
|
62
61
|
------------------------------------------------------------------------------------
|
63
62
|
|
64
|
-
With Ruby (version 2.
|
65
|
-
need to issue :
|
63
|
+
With Ruby (version 2.3 or higher) and rubygems properly installed, you only need :
|
66
64
|
|
67
65
|
```
|
68
66
|
gem install rest-ftp-daemon
|
@@ -74,19 +72,19 @@ If that is not the case yet, see section [Debian install preparation](#debian-in
|
|
74
72
|
Usage
|
75
73
|
------------------------------------------------------------------------------------
|
76
74
|
|
77
|
-
You must provide a configuration file for the daemon to start, either
|
78
|
-
|
79
|
-
|
75
|
+
You must provide a configuration file for the daemon to start, either explicitly using
|
76
|
+
option `--config` or implicitly at `/etc/rest-ftp-daemon.yml`. A sample file is provided, issue
|
77
|
+
`--help` to get more info.
|
80
78
|
|
81
|
-
You
|
79
|
+
You then simply start the daemon on its standard port, or on a specific port using `-p`
|
82
80
|
|
83
81
|
```
|
84
82
|
$ rest-ftp-daemon -p 3000 start
|
85
83
|
```
|
86
84
|
|
87
|
-
Check that the daemon is running and exposes a JSON status structure
|
85
|
+
Check that the daemon is running and exposes a JSON status structure at `http://localhost:3000/status`.
|
88
86
|
|
89
|
-
The dashboard will provide
|
87
|
+
The dashboard will provide an overview at `http://localhost:3000/`
|
90
88
|
|
91
89
|
If the daemon appears to exit quickly when launched, it may be caused by logfiles that can't be written (check files permissions or owner).
|
92
90
|
|
@@ -106,7 +104,7 @@ Launcher options :
|
|
106
104
|
| -v | --version | | Show the current version |
|
107
105
|
|
108
106
|
|
109
|
-
|
107
|
+
Usage and examples
|
110
108
|
------------------------------------------------------------------------------------
|
111
109
|
|
112
110
|
#### Start a job to transfer a file named "file.iso" to a local FTP server
|
@@ -141,11 +139,13 @@ curl -H "Content-Type: application/json" -X POST -D /dev/stdout -d \
|
|
141
139
|
|
142
140
|
#### Start a job with a specific pool name
|
143
141
|
|
142
|
+
The daemon spawns groups of workers (worker pools) to work on groups of jobs (job pools). Any ```pool``` attribute not declared in configuration will land into the ```"default"``` pool.
|
143
|
+
|
144
144
|
```
|
145
145
|
curl -H "Content-Type: application/json" -X POST -D /dev/stdout -d \
|
146
146
|
'{"pool": "maxxxxx",source":"~/file.iso",target":"ftp://anonymous@localhost/incoming/dest2.iso"}' "http://localhost:3000/jobs"
|
147
147
|
```
|
148
|
-
This job will be handled by the "maxxxxx" workers only, or by the default worker is this pool is not declared.
|
148
|
+
This job will be handled by the "maxxxxx" workers only, or by the ```"default"``` worker is this pool is not declared.
|
149
149
|
|
150
150
|
|
151
151
|
#### Get info about a job with ID="q89j.1"
|
@@ -221,27 +221,33 @@ TODO for this document
|
|
221
221
|
Debian install preparation
|
222
222
|
------------------------------------------------------------------------------------
|
223
223
|
|
224
|
-
This project is available as a rubygem, requires Ruby 2.
|
224
|
+
This project is available as a rubygem, requires Ruby 2.3 and rubygems installed.
|
225
|
+
|
226
|
+
#### Using rbenv and ruby-build
|
225
227
|
|
226
|
-
You may use `rbenv` and `ruby-build` to get the right Ruby version. If this is your case, ensure that ruby-build definitions are up-to-date and include
|
228
|
+
You may use `rbenv` and `ruby-build` to get the right Ruby version. If this is your case, ensure that ruby-build definitions are up-to-date and include the right Ruby version.
|
227
229
|
|
228
230
|
```
|
229
|
-
#
|
230
|
-
# ruby-build
|
231
|
+
# git clone https://github.com/rbenv/rbenv.git ~/.rbenv
|
232
|
+
# git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
|
233
|
+
# echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
|
234
|
+
# echo 'eval "$(rbenv init -)"' >> ~/.bashrc
|
235
|
+
# ruby-build --definitions | grep '2.3'
|
231
236
|
```
|
232
237
|
|
233
|
-
Otherwise, you way have to update ruby-build to include Ruby 2.
|
234
|
-
On Debian, 2.
|
238
|
+
Otherwise, you way have to update ruby-build to include Ruby 2.3.0 definitions.
|
239
|
+
On Debian, 2.3.0 is not included in Wheezy and appears in Jessie's version of the package.
|
240
|
+
|
241
|
+
#### Dedicated user
|
235
242
|
|
236
243
|
Use a dedicated user for the daemon, switch to this user and enable rbenv
|
237
244
|
|
238
245
|
```
|
239
246
|
# adduser --disabled-password --gecos "" rftpd
|
240
247
|
# su rftpd -l
|
241
|
-
# echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
|
242
|
-
# echo 'eval "$(rbenv init -)"' >> ~/.bashrc
|
243
248
|
```
|
244
249
|
|
250
|
+
#### Ruby version
|
245
251
|
|
246
252
|
Install the right ruby version and activate it
|
247
253
|
|
@@ -251,6 +257,8 @@ Install the right ruby version and activate it
|
|
251
257
|
# rbenv rehash
|
252
258
|
```
|
253
259
|
|
260
|
+
#### Daemon installation
|
261
|
+
|
254
262
|
Update RubyGems and install the gem from rubygems.org
|
255
263
|
|
256
264
|
```
|
data/bin/rest-ftp-daemon
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
# Try to load external libs
|
4
|
-
app_root = File.expand_path File.dirname(__FILE__) + "/../"
|
3
|
+
# Try to load external libs, helpers and constants
|
5
4
|
begin
|
6
5
|
require "thin"
|
7
6
|
require "optparse"
|
@@ -11,11 +10,8 @@ begin
|
|
11
10
|
rescue LoadError
|
12
11
|
raise "EXITING: some of basic libs were not found: thin, optparse, socket, settingslogic"
|
13
12
|
end
|
14
|
-
|
15
|
-
|
16
|
-
# Load helpers and constants
|
17
13
|
[:constants, :helpers].each do |lib|
|
18
|
-
|
14
|
+
require_relative "../lib/rest-ftp-daemon/#{lib}"
|
19
15
|
end
|
20
16
|
puts
|
21
17
|
|
@@ -57,11 +53,12 @@ end
|
|
57
53
|
# Load config, and merge options from ARGV into settings
|
58
54
|
# FIXME: file configuration detection could reside in settings.rb
|
59
55
|
APP_CONF ||= DEFAULT_CONFIG_PATH
|
60
|
-
APP_ENV ||=
|
56
|
+
APP_ENV ||= ENV_PRODUCTION
|
61
57
|
abort "EXITING: cannot read configuration file: #{APP_CONF}" unless File.exist? APP_CONF
|
62
58
|
begin
|
63
59
|
# Import settings
|
64
|
-
require File.expand_path("#{app_root}/lib/rest-ftp-daemon/settings")
|
60
|
+
# require File.expand_path("#{app_root}/lib/rest-ftp-daemon/settings")
|
61
|
+
require_relative "../lib/rest-ftp-daemon/settings"
|
65
62
|
|
66
63
|
# Set defaults
|
67
64
|
Settings.init_defaults
|
@@ -129,6 +126,7 @@ puts
|
|
129
126
|
|
130
127
|
# Start Thin with this rackup configuration, changing to app_root first
|
131
128
|
begin
|
129
|
+
app_root = File.expand_path(File.dirname(__FILE__) + "/../")
|
132
130
|
Dir.chdir app_root
|
133
131
|
Thin::Runner.new(argv.flatten).run!
|
134
132
|
rescue RuntimeError => e
|
data/config.ru
CHANGED
@@ -23,8 +23,8 @@ GC::Profiler.enable if Settings.newrelic_enabled?
|
|
23
23
|
use Rack::Static, urls: ["/css", "/js", "/images"], root: "#{APP_LIBS}/static/"
|
24
24
|
|
25
25
|
# Rack reloader and mini-profiler
|
26
|
-
unless Settings.namespace ==
|
27
|
-
use Rack::Reloader,
|
26
|
+
unless Settings.namespace == ENV_PRODUCTION
|
27
|
+
use Rack::Reloader, 1
|
28
28
|
# use Rack::MiniProfiler
|
29
29
|
end
|
30
30
|
|
data/lib/rest-ftp-daemon.rb
CHANGED
@@ -11,13 +11,6 @@ require "thread"
|
|
11
11
|
require "singleton"
|
12
12
|
require "newrelic_rpm"
|
13
13
|
|
14
|
-
# Development libs /?pp=flamegraph
|
15
|
-
# unless Settings.namespace == "production"
|
16
|
-
# require 'rack-mini-profiler'
|
17
|
-
# # require 'stackprof'
|
18
|
-
# require 'flamegraph'
|
19
|
-
# end
|
20
|
-
|
21
14
|
# Project's libs
|
22
15
|
require_relative "rest-ftp-daemon/constants"
|
23
16
|
require_relative "rest-ftp-daemon/array"
|
@@ -23,53 +23,65 @@ module RestFtpDaemon
|
|
23
23
|
#:encoding => Encoding::ASCII_8BIT
|
24
24
|
haml_engine.render(binding, values)
|
25
25
|
end
|
26
|
+
|
27
|
+
def build_dashboard filter = ''
|
28
|
+
# Initialize Facter
|
29
|
+
Facter.loadfacts
|
30
|
+
|
31
|
+
# Detect QS filters
|
32
|
+
@filter = filter.to_s
|
33
|
+
@page = params["page"].to_i
|
34
|
+
|
35
|
+
# Get jobs for this view, order jobs by their weights
|
36
|
+
jobs_with_status = $queue.jobs_with_status(filter).reverse
|
37
|
+
|
38
|
+
# Provide queue only if no filtering set
|
39
|
+
if filter.empty?
|
40
|
+
@jobs_queued = $queue.jobs_queued
|
41
|
+
else
|
42
|
+
@jobs_queued = []
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get workers status
|
46
|
+
@worker_variables = $pool.worker_variables
|
47
|
+
|
48
|
+
# Build paginator
|
49
|
+
@paginate = Paginate.new jobs_with_status
|
50
|
+
@paginate.filter = filter
|
51
|
+
@paginate.page = @page
|
52
|
+
@paginate.all = params.keys.include? "all"
|
53
|
+
|
54
|
+
# Compile haml template
|
55
|
+
output = render :dashboard
|
56
|
+
|
57
|
+
# Send response
|
58
|
+
env["api.format"] = :html
|
59
|
+
format "html"
|
60
|
+
status 200
|
61
|
+
content_type "text/html"
|
62
|
+
body output
|
63
|
+
end
|
64
|
+
|
26
65
|
end
|
27
66
|
|
28
67
|
|
29
68
|
### Common request logging
|
30
|
-
|
31
69
|
before do
|
32
70
|
log_info "HTTP #{request.request_method} #{request.fullpath}", params
|
33
71
|
end
|
34
72
|
|
35
73
|
|
36
74
|
### DASHBOARD
|
37
|
-
|
75
|
+
desc "Show a global dashboard"
|
38
76
|
get "/" do
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
# Detect QS filters
|
43
|
-
@only = params["only"].to_s
|
44
|
-
|
45
|
-
# Get jobs for this view, order jobs by their weights
|
46
|
-
jobs_with_status = $queue.jobs_with_status(@only).reverse
|
47
|
-
|
48
|
-
# Provide queue only if no filtering set
|
49
|
-
if @only.empty?
|
50
|
-
@jobs_queued = $queue.jobs_queued
|
51
|
-
else
|
52
|
-
@jobs_queued = []
|
53
|
-
end
|
54
|
-
|
55
|
-
# Get workers status
|
56
|
-
@worker_variables = $pool.worker_variables
|
57
|
-
|
58
|
-
# Build paginator
|
59
|
-
@paginate = Paginate.new jobs_with_status
|
60
|
-
@paginate.only = params["only"]
|
61
|
-
@paginate.page = params["page"]
|
62
|
-
@paginate.all = params.keys.include? "all"
|
63
|
-
|
64
|
-
# Compile haml template
|
65
|
-
output = render :dashboard
|
77
|
+
build_dashboard()
|
78
|
+
end
|
66
79
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
body output
|
80
|
+
params do
|
81
|
+
optional :filter, type: String, desc: "Filter for the jobs list"#, regexp: /[^\/]+/
|
82
|
+
end
|
83
|
+
get ":filter" do
|
84
|
+
build_dashboard(params["filter"])
|
73
85
|
end
|
74
86
|
|
75
87
|
end
|
@@ -16,8 +16,8 @@ module RestFtpDaemon
|
|
16
16
|
format :json
|
17
17
|
content_type :json, 'application/json; charset=utf-8'
|
18
18
|
|
19
|
-
mount RestFtpDaemon::API::Jobs =>
|
20
|
-
mount RestFtpDaemon::API::Dashbaord =>
|
19
|
+
mount RestFtpDaemon::API::Jobs => MOUNT_JOBS
|
20
|
+
mount RestFtpDaemon::API::Dashbaord => MOUNT_BOARD
|
21
21
|
|
22
22
|
|
23
23
|
### INITIALIZATION
|
@@ -48,6 +48,13 @@ module RestFtpDaemon
|
|
48
48
|
end
|
49
49
|
|
50
50
|
|
51
|
+
### ROOT URL ACCESS
|
52
|
+
|
53
|
+
get "/" do
|
54
|
+
redirect Helpers.dashboard_filter_url()
|
55
|
+
end
|
56
|
+
|
57
|
+
|
51
58
|
### SHOW ROUTES
|
52
59
|
|
53
60
|
desc "Show application routes"
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# Terrific constants
|
2
2
|
APP_NAME = "rest-ftp-daemon"
|
3
3
|
APP_NICK = "rftpd"
|
4
|
-
APP_VER = "0.
|
4
|
+
APP_VER = "0.246.0"
|
5
5
|
|
6
6
|
# Provide default config file information
|
7
|
-
APP_LIB = File.expand_path
|
7
|
+
APP_LIB = File.expand_path(File.dirname(__FILE__))
|
8
8
|
APP_ROOT = File.expand_path(File.dirname(__FILE__) + "/../../")
|
9
9
|
|
10
10
|
DEFAULT_CONFIG_PATH = File.expand_path "/etc/#{APP_NAME}.yml"
|
@@ -36,7 +36,7 @@ JOB_TEMPFILE_LEN = 8
|
|
36
36
|
JOB_UPDATE_INTERVAL = 1
|
37
37
|
|
38
38
|
|
39
|
-
# Jobs
|
39
|
+
# Jobs statuses
|
40
40
|
JOB_STATUS_PREPARING = "preparing"
|
41
41
|
JOB_STATUS_RUNNING = "running"
|
42
42
|
JOB_STATUS_CHECKING_SRC = "checking_source"
|
@@ -49,7 +49,15 @@ JOB_STATUS_DISCONNECTING= "remote_disconnect"
|
|
49
49
|
JOB_STATUS_FINISHED = "finished"
|
50
50
|
JOB_STATUS_FAILED = "failed"
|
51
51
|
JOB_STATUS_QUEUED = "queued"
|
52
|
+
JOB_STYLES = {
|
53
|
+
JOB_STATUS_QUEUED => :active,
|
54
|
+
JOB_STATUS_FAILED => :warning,
|
55
|
+
JOB_STATUS_FINISHED => :success,
|
56
|
+
JOB_STATUS_UPLOADING => :info,
|
57
|
+
JOB_STATUS_RENAMING => :info,
|
58
|
+
}
|
52
59
|
|
60
|
+
# Worker statuses
|
53
61
|
WORKER_STATUS_STARTING = "starting"
|
54
62
|
WORKER_STATUS_WAITING = "waiting"
|
55
63
|
WORKER_STATUS_RUNNING = "running"
|
@@ -57,6 +65,12 @@ WORKER_STATUS_FINISHED = "finished"
|
|
57
65
|
WORKER_STATUS_TIMEOUT = "timeout"
|
58
66
|
WORKER_STATUS_CRASHED = "crashed"
|
59
67
|
WORKER_STATUS_CLEANING = "cleaning"
|
68
|
+
WORKER_STYLES = {
|
69
|
+
WORKER_STATUS_WAITING => :success,
|
70
|
+
WORKER_STATUS_RUNNING => :info,
|
71
|
+
WORKER_STATUS_CRASHED => :danger,
|
72
|
+
WORKER_STATUS_FINISHED => :success,
|
73
|
+
}
|
60
74
|
|
61
75
|
|
62
76
|
# Logging and startup
|
@@ -75,6 +89,10 @@ LOG_INDENT = "\t"
|
|
75
89
|
BIND_PORT_TIMEOUT = 3
|
76
90
|
BIND_PORT_LOCALHOST = "127.0.0.1"
|
77
91
|
|
92
|
+
ENV_PRODUCTION = "production"
|
93
|
+
MOUNT_JOBS = "/jobs"
|
94
|
+
MOUNT_BOARD = "/board"
|
95
|
+
|
78
96
|
|
79
97
|
# Notifications
|
80
98
|
NOTIFY_PREFIX = "rftpd"
|
@@ -82,22 +100,6 @@ NOTIFY_USERAGENT = "#{APP_NAME}/v#{APP_VER}"
|
|
82
100
|
NOTIFY_IDENTIFIER_LEN = 4
|
83
101
|
|
84
102
|
|
85
|
-
# Dashboard row styles
|
86
|
-
DASHBOARD_JOB_STYLES = {
|
87
|
-
JOB_STATUS_QUEUED => :active,
|
88
|
-
JOB_STATUS_FAILED => :warning,
|
89
|
-
JOB_STATUS_FINISHED => :success,
|
90
|
-
JOB_STATUS_UPLOADING => :info,
|
91
|
-
JOB_STATUS_RENAMING => :info,
|
92
|
-
}
|
93
|
-
DASHBOARD_WORKER_STYLES = {
|
94
|
-
WORKER_STATUS_WAITING => :success,
|
95
|
-
WORKER_STATUS_RUNNING => :info,
|
96
|
-
WORKER_STATUS_CRASHED => :danger,
|
97
|
-
WORKER_STATUS_FINISHED => :success,
|
98
|
-
}
|
99
|
-
|
100
|
-
|
101
103
|
# Initialize defaults
|
102
104
|
APP_STARTED = Time.now
|
103
105
|
APP_LIBS = File.dirname(__FILE__)
|
@@ -132,8 +132,12 @@ module RestFtpDaemon
|
|
132
132
|
out.join(" ")
|
133
133
|
end
|
134
134
|
|
135
|
-
def self.
|
136
|
-
"
|
135
|
+
def self.dashboard_job_url job
|
136
|
+
"#{MOUNT_JOBS}/#{job.id}" if job.respond_to? :id
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.dashboard_filter_url filter = ''
|
140
|
+
"#{MOUNT_BOARD}/#{filter}"
|
137
141
|
end
|
138
142
|
|
139
143
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RestFtpDaemon
|
2
2
|
class Paginate
|
3
3
|
|
4
|
-
attr_writer :
|
4
|
+
attr_writer :filter
|
5
5
|
attr_accessor :all
|
6
6
|
|
7
7
|
def initialize data
|
@@ -9,7 +9,7 @@ module RestFtpDaemon
|
|
9
9
|
@pages = 0
|
10
10
|
@total = 0
|
11
11
|
@data = []
|
12
|
-
@
|
12
|
+
@filter = ''
|
13
13
|
@page = 1
|
14
14
|
@pages = 1
|
15
15
|
@all = false
|
@@ -53,9 +53,11 @@ module RestFtpDaemon
|
|
53
53
|
def link p
|
54
54
|
klass = (p == @page)? " btn-info" : ""
|
55
55
|
|
56
|
-
|
56
|
+
url = Helpers.dashboard_filter_url(@filter)
|
57
|
+
|
58
|
+
"<a class='paginate btn btn-default%s' href='%s?page=%d'>%p</a>" % [
|
57
59
|
klass,
|
58
|
-
@
|
60
|
+
@filter,
|
59
61
|
p,
|
60
62
|
p
|
61
63
|
]
|
@@ -8,13 +8,13 @@
|
|
8
8
|
|
9
9
|
.col-md-4
|
10
10
|
.btn-group.btn-group-sm
|
11
|
-
- klass = @
|
12
|
-
%a.btn.btn-default{href:
|
11
|
+
- klass = @filter.empty? ? "btn-info" : ""
|
12
|
+
%a.btn.btn-default{href: Helpers.dashboard_filter_url(), class: klass}
|
13
13
|
ALL (#{counts_all})
|
14
14
|
.btn-group.btn-group-sm
|
15
15
|
- counts_by_status.each do |status, count|
|
16
|
-
- klass = (status.to_s == @
|
17
|
-
%a.btn.btn-default{href:
|
16
|
+
- klass = (status.to_s == @filter) ? "btn-info" : ""
|
17
|
+
%a.btn.btn-default{href: Helpers.dashboard_filter_url(status), class: klass}
|
18
18
|
#{status} (#{count})
|
19
19
|
|
20
20
|
.col-md-8
|
@@ -5,7 +5,7 @@
|
|
5
5
|
- source_processed = job.get(:source_processed) || 0
|
6
6
|
- source_current = job.get(:source_current)
|
7
7
|
- bitrate = job.get :transfer_bitrate
|
8
|
-
- trclass =
|
8
|
+
- trclass = JOB_STYLES[job.status]
|
9
9
|
- runs = job.runs.to_i
|
10
10
|
|
11
11
|
- unless job.error.nil?
|
@@ -13,7 +13,7 @@
|
|
13
13
|
|
14
14
|
%tr{class: trclass.to_s}
|
15
15
|
%td
|
16
|
-
%a{href: Helpers.
|
16
|
+
%a{href: Helpers.dashboard_job_url(job)}
|
17
17
|
%b= job.id
|
18
18
|
|
19
19
|
%td= job.label
|
@@ -14,7 +14,7 @@
|
|
14
14
|
- wid = vars[:wid]
|
15
15
|
- status = vars[:status]
|
16
16
|
- alive = $pool.worker_alive? wid
|
17
|
-
- trclass =
|
17
|
+
- trclass = WORKER_STYLES[status]
|
18
18
|
|
19
19
|
- unless alive
|
20
20
|
- trclass = "danger"
|
@@ -28,8 +28,8 @@
|
|
28
28
|
%td= vars[:jid]
|
29
29
|
%td.text-right
|
30
30
|
|
31
|
-
- if vars[:
|
32
|
-
- no_news_for = (Time.now - vars[:
|
31
|
+
- if vars[:updated_at].is_a? Time
|
32
|
+
- no_news_for = (Time.now - vars[:updated_at]).round(0)
|
33
33
|
= Helpers.formatted_duration no_news_for
|
34
34
|
- else
|
35
35
|
= "?"
|
@@ -46,7 +46,7 @@ module RestFtpDaemon
|
|
46
46
|
def worker_status status, job = nil
|
47
47
|
# Update thread variables
|
48
48
|
Thread.current.thread_variable_set :status, status
|
49
|
-
Thread.current.thread_variable_set :
|
49
|
+
Thread.current.thread_variable_set :updated_at, Time.now
|
50
50
|
|
51
51
|
# Nothin' to log if "silent"
|
52
52
|
return unless @log_worker_status_changes
|
@@ -61,7 +61,7 @@ module RestFtpDaemon
|
|
61
61
|
|
62
62
|
def worker_jid jid
|
63
63
|
Thread.current.thread_variable_set :jid, jid
|
64
|
-
Thread.current.thread_variable_set :
|
64
|
+
Thread.current.thread_variable_set :updated_at, Time.now
|
65
65
|
end
|
66
66
|
|
67
67
|
end
|
data/rest-ftp-daemon.gemspec
CHANGED
@@ -2,7 +2,7 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Dashboard", feature: true do
|
4
4
|
|
5
|
-
describe "GET
|
5
|
+
describe "GET #{MOUNT_BOARD}" do
|
6
6
|
context 'without a password' do
|
7
7
|
it 'is forbidden' do
|
8
8
|
expect(HTTP.accept(:json).get("http://localhost:#{RequestHelpers::PORT}").status).to eq 401
|
@@ -12,14 +12,14 @@ describe "Dashboard", feature: true do
|
|
12
12
|
context "with a password" do
|
13
13
|
it "can be accessed" do
|
14
14
|
expect(
|
15
|
-
get(
|
15
|
+
get(MOUNT_BOARD).status
|
16
16
|
).to eq 200
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
it "has an HTML representation" do
|
21
21
|
expect(
|
22
|
-
get(
|
22
|
+
get(MOUNT_BOARD, accept: 'html').status
|
23
23
|
).to eq 200
|
24
24
|
end
|
25
25
|
end # GET /
|
@@ -2,8 +2,8 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe "Jobs", feature: true do
|
4
4
|
|
5
|
-
describe "GET
|
6
|
-
let!(:response) { get
|
5
|
+
describe "GET #{MOUNT_JOBS}" do
|
6
|
+
let!(:response) { get MOUNT_JOBS }
|
7
7
|
|
8
8
|
it "responds successfully" do
|
9
9
|
expect(response.status).to eq 200
|
@@ -14,9 +14,9 @@ describe "Jobs", feature: true do
|
|
14
14
|
end
|
15
15
|
end # GET /jobs
|
16
16
|
|
17
|
-
describe "POST
|
17
|
+
describe "POST #{MOUNT_JOBS}" do
|
18
18
|
def jobs_list
|
19
|
-
JSON.parse get(
|
19
|
+
JSON.parse get(MOUNT_JOBS).body
|
20
20
|
end
|
21
21
|
|
22
22
|
context "when params are valid" do
|
@@ -24,43 +24,55 @@ describe "Jobs", feature: true do
|
|
24
24
|
{
|
25
25
|
source: "/tmp/foo",
|
26
26
|
target: "/tmp/bar",
|
27
|
+
priority: 6,
|
28
|
+
pool: "pool666",
|
27
29
|
}
|
28
30
|
end
|
29
31
|
|
30
32
|
it "issues a 201 response" do
|
31
33
|
expect(
|
32
|
-
post(
|
34
|
+
post(MOUNT_JOBS, json: params).status,
|
33
35
|
).to eq 201
|
34
36
|
end
|
35
37
|
|
36
38
|
it "exposes the new job id" do
|
37
|
-
response = JSON.parse post(
|
39
|
+
response = JSON.parse post(MOUNT_JOBS, json: params)
|
38
40
|
expect(response["id"]).not_to be_nil
|
39
41
|
end
|
40
42
|
|
41
43
|
it "assigns a status" do
|
42
|
-
response = JSON.parse post(
|
44
|
+
response = JSON.parse post(MOUNT_JOBS, json: params)
|
43
45
|
expect(response["status"]).to match(/^(queued|failed)$/)
|
44
46
|
end
|
45
47
|
|
48
|
+
it "assigns a pool" do
|
49
|
+
response = JSON.parse post(MOUNT_JOBS, json: params)
|
50
|
+
expect(response["pool"]).to match(/^(default|pool666)$/)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "assigns a priority" do
|
54
|
+
response = JSON.parse post(MOUNT_JOBS, json: params)
|
55
|
+
expect(response["priority"]).to eq 6
|
56
|
+
end
|
57
|
+
|
46
58
|
it "creates a new job" do
|
47
59
|
expect {
|
48
|
-
post(
|
60
|
+
post(MOUNT_JOBS, json: params)
|
49
61
|
}.to change { jobs_list.size }.by(1)
|
50
62
|
end
|
51
63
|
end
|
52
64
|
end # POST /jobs
|
53
65
|
|
54
|
-
describe "GET
|
66
|
+
describe "GET #{MOUNT_JOBS}/:id" do
|
55
67
|
let(:creation_response) do
|
56
|
-
JSON.parse post(
|
68
|
+
JSON.parse post(MOUNT_JOBS, json: { source: "/tmp/foo", target: "/tmp/bar" }).body
|
57
69
|
end
|
58
70
|
|
59
71
|
let(:job_id) { creation_response.fetch("id") }
|
60
72
|
|
61
73
|
it "is properly exposed" do
|
62
74
|
expect(
|
63
|
-
get("
|
75
|
+
get("#{MOUNT_JOBS}/#{job_id}").status,
|
64
76
|
).to eq 200
|
65
77
|
end
|
66
78
|
end # GET /jobs/:id
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
require "pathname"
|
2
2
|
require "http"
|
3
|
-
require_relative "support/request_helpers"
|
4
3
|
require "pry"
|
5
4
|
|
5
|
+
require_relative "support/request_helpers"
|
6
|
+
require_relative "../lib/rest-ftp-daemon/constants"
|
7
|
+
|
6
8
|
RSpec.configure do |config|
|
7
9
|
# rspec-expectations config goes here. You can use an alternate
|
8
10
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
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.246.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-01-
|
11
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|