rest-ftp-daemon 0.245.1 → 0.246.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 +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
|