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
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,78 +1,81 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
rest-ftp-daemon (0.55)
|
5
|
-
facter
|
6
|
-
grape
|
7
|
-
json
|
8
|
-
settingslogic
|
9
|
-
thin (~> 1.6)
|
10
|
-
|
11
1
|
GEM
|
12
2
|
remote: http://rubygems.org/
|
13
3
|
specs:
|
14
|
-
|
15
|
-
activesupport (4.1.6)
|
4
|
+
activesupport (4.1.4)
|
16
5
|
i18n (~> 0.6, >= 0.6.9)
|
17
6
|
json (~> 1.7, >= 1.7.7)
|
18
7
|
minitest (~> 5.1)
|
19
8
|
thread_safe (~> 0.1)
|
20
9
|
tzinfo (~> 1.1)
|
21
|
-
|
22
|
-
descendants_tracker (~> 0.0.4)
|
23
|
-
ice_nine (~> 0.11.0)
|
24
|
-
thread_safe (~> 0.3, >= 0.3.1)
|
10
|
+
addressable (2.3.6)
|
25
11
|
builder (3.2.2)
|
26
|
-
coercible (1.0.0)
|
27
|
-
descendants_tracker (~> 0.0.1)
|
28
|
-
daemons (1.1.9)
|
29
12
|
descendants_tracker (0.0.4)
|
30
13
|
thread_safe (~> 0.3, >= 0.3.1)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
hashie (>= 2
|
39
|
-
multi_json (>= 1.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
virtus (>= 1.0.0)
|
45
|
-
hashie (3.3.1)
|
14
|
+
faraday (0.9.0)
|
15
|
+
multipart-post (>= 1.2, < 3)
|
16
|
+
git (1.2.8)
|
17
|
+
github_api (0.12.0)
|
18
|
+
addressable (~> 2.3)
|
19
|
+
descendants_tracker (~> 0.0.4)
|
20
|
+
faraday (~> 0.8, < 0.10)
|
21
|
+
hashie (>= 3.2)
|
22
|
+
multi_json (>= 1.7.5, < 2.0)
|
23
|
+
nokogiri (~> 1.6.3)
|
24
|
+
oauth2
|
25
|
+
hashie (3.2.0)
|
26
|
+
highline (1.6.21)
|
46
27
|
i18n (0.6.11)
|
47
|
-
|
28
|
+
jeweler (2.0.1)
|
29
|
+
builder
|
30
|
+
bundler (>= 1.0)
|
31
|
+
git (>= 1.2.5)
|
32
|
+
github_api
|
33
|
+
highline (>= 1.6.15)
|
34
|
+
nokogiri (>= 1.5.10)
|
35
|
+
rake
|
36
|
+
rdoc
|
48
37
|
json (1.8.1)
|
49
|
-
|
38
|
+
jwt (1.0.0)
|
39
|
+
mini_portile (0.6.0)
|
40
|
+
minitest (5.4.0)
|
50
41
|
multi_json (1.10.1)
|
51
42
|
multi_xml (0.5.5)
|
43
|
+
multipart-post (2.0.0)
|
44
|
+
nokogiri (1.6.3.1)
|
45
|
+
mini_portile (= 0.6.0)
|
46
|
+
oauth2 (1.0.0)
|
47
|
+
faraday (>= 0.8, < 0.10)
|
48
|
+
jwt (~> 1.0)
|
49
|
+
multi_json (~> 1.3)
|
50
|
+
multi_xml (~> 0.5)
|
51
|
+
rack (~> 1.2)
|
52
52
|
rack (1.5.2)
|
53
|
-
rack-
|
54
|
-
rack
|
55
|
-
rack-mount (0.8.3)
|
56
|
-
rack (>= 1.0.0)
|
53
|
+
rack-protection (1.5.3)
|
54
|
+
rack
|
57
55
|
rake (10.3.2)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
rdoc (4.1.1)
|
57
|
+
json (~> 1.4)
|
58
|
+
shoulda (3.5.0)
|
59
|
+
shoulda-context (~> 1.0, >= 1.0.1)
|
60
|
+
shoulda-matchers (>= 1.4.1, < 3.0)
|
61
|
+
shoulda-context (1.2.1)
|
62
|
+
shoulda-matchers (2.6.2)
|
63
|
+
activesupport (>= 3.0.0)
|
64
|
+
sinatra (1.4.5)
|
65
|
+
rack (~> 1.4)
|
66
|
+
rack-protection (~> 1.4)
|
67
|
+
tilt (~> 1.3, >= 1.3.4)
|
63
68
|
thread_safe (0.3.4)
|
64
|
-
|
69
|
+
tilt (1.4.1)
|
70
|
+
tzinfo (1.2.1)
|
65
71
|
thread_safe (~> 0.1)
|
66
|
-
virtus (1.0.3)
|
67
|
-
axiom-types (~> 0.1)
|
68
|
-
coercible (~> 1.0)
|
69
|
-
descendants_tracker (~> 0.0, >= 0.0.3)
|
70
|
-
equalizer (~> 0.0, >= 0.0.9)
|
71
72
|
|
72
73
|
PLATFORMS
|
73
74
|
ruby
|
74
75
|
|
75
76
|
DEPENDENCIES
|
76
|
-
bundler (~> 1.
|
77
|
-
|
78
|
-
|
77
|
+
bundler (~> 1.0)
|
78
|
+
jeweler (~> 2.0.1)
|
79
|
+
json
|
80
|
+
shoulda
|
81
|
+
sinatra
|
data/README.md
CHANGED
@@ -1,46 +1,25 @@
|
|
1
1
|
rest-ftp-daemon
|
2
2
|
====================================================================================
|
3
3
|
|
4
|
-
|
5
|
-
|
6
4
|
This is a pretty simple FTP client daemon, controlled through a RESTfull API.
|
7
5
|
|
8
6
|
As of today, its main features are :
|
9
7
|
|
10
|
-
*
|
11
|
-
* Delegate a transfer job by ``POST```'ing a simple JSON structure
|
8
|
+
* Delegate a transfer job, ```PUT```'ing posting simple JSON structure
|
12
9
|
* Spawn a dedicated thread to handle this job in its own context
|
13
|
-
* Report transfer status, progress and errors for each job
|
10
|
+
* Report transfer status, progress and errors for each delegated job
|
14
11
|
* Expose JSON status of workers on ```GET /jobs/``` for automated monitoring
|
15
|
-
* Parralelize jobs as soon as they arrive
|
16
|
-
* Handle job queues and priority as an attribute of the job
|
17
|
-
* Allow dynamic evaluation of priorities, and change of any attribute until the job is picked
|
18
|
-
* Provide RESTful notifications to the requesting client
|
19
|
-
* Allow authentication in FTP target in a standard URI-format
|
20
|
-
* Allow configuration-based path templates to abstract local mounts or remote FTPs (endpoint tokens)
|
21
|
-
|
22
|
-
|
23
|
-
Expected features in a short-time range :
|
24
|
-
|
25
|
-
* Allow change of priorities or other attributes after a job has been started
|
26
|
-
* Offer a basic dashboard directly within the daemon HTTP interface
|
27
|
-
* Periodically send an update-notification with transfer status and progress
|
28
|
-
* Allow fallback file source when first file path is unavailable (failover)
|
29
|
-
* Provide swagger-style API documentation
|
30
|
-
* Authenticate API clients
|
31
|
-
|
32
12
|
|
33
13
|
|
34
14
|
Installation
|
35
15
|
------------------------------------------------------------------------------------
|
36
16
|
|
37
|
-
This project is available as a rubygem, requires on ruby >= 1.9
|
17
|
+
This project is available as a rubygem, requires on ruby >= 1.9 and rubygems installed.
|
38
18
|
|
39
19
|
Get and install the gem from rubygems.org:
|
40
20
|
|
41
21
|
```
|
42
|
-
|
43
|
-
gem install rest-ftp-daemon --no-ri --no-rdoc
|
22
|
+
gem install rest-ftp-daemon
|
44
23
|
```
|
45
24
|
|
46
25
|
Start the daemon:
|
@@ -49,117 +28,49 @@ Start the daemon:
|
|
49
28
|
rest-ftp-daemon start
|
50
29
|
```
|
51
30
|
|
52
|
-
Start the daemon on a specific port :
|
53
|
-
|
54
|
-
```
|
55
|
-
rest-ftp-daemon -p4000 start
|
56
|
-
```
|
57
|
-
|
58
31
|
Check that the daemon is running and giving status info
|
59
32
|
|
60
33
|
```
|
61
34
|
http://localhost:3000/
|
62
35
|
```
|
63
36
|
|
64
|
-
|
65
|
-
------------------------------------------------------------------------------------
|
66
|
-
Most of the configuration options live in a YAML configuration file, containing two main sections:
|
67
|
-
|
68
|
-
* the ``defaults`` section should be left as-is and will be used is no other environment-specific value is provided.
|
69
|
-
* the ``production`` section can receive personnalized settings according to your environment-specific setup and paths.
|
70
|
-
|
71
|
-
Configuration priority is defined as follows (from most important to last resort):
|
72
|
-
|
73
|
-
* command-line parameters
|
74
|
-
* config file defaults section
|
75
|
-
* config file environment section
|
76
|
-
* application internal defaults
|
77
|
-
|
78
|
-
|
79
|
-
As a starting point, ``rest-ftp-daemon.yml.sample`` is an exemple config file that can be copied into the expected location ``/etc/rest-ftp-daemon.yml``.
|
80
|
-
|
81
|
-
|
82
|
-
Logging
|
83
|
-
------------------------------------------------------------------------------------
|
84
|
-
|
85
|
-
The application will not log to any file by default, if not specified in its configuration.
|
86
|
-
Otherwise separate logging paths can be provided for the Thin webserver, API related messages, and workers related messages. Providing and empty value will simply activate logging to ``STDOUT``.
|
37
|
+
For now, daemon logs to ```APP_LOGTO``` defined in ```lib/config.rb```
|
87
38
|
|
88
39
|
|
89
40
|
Usage examples
|
90
41
|
------------------------------------------------------------------------------------
|
91
42
|
|
92
|
-
|
43
|
+
Start a job to transfer a file named "file.ova" to a local FTP server
|
93
44
|
|
94
45
|
```
|
95
46
|
curl -H "Content-Type: application/json" -X POST -D /dev/stdout -d \
|
96
|
-
'{"source":"~/file.
|
47
|
+
'{"source":"~/file.ova","target":"ftp://anonymous@localhost/incoming/dest2.ova"}' "http://localhost:3000/jobs"
|
97
48
|
```
|
98
49
|
|
99
|
-
|
100
|
-
This URL will be called at some points, ``POST```'ing a generic JSON structure with progress information.
|
101
|
-
|
102
|
-
|
103
|
-
* Start a job requesting notifications ``POST```'ed on "http://requestb.in/1321axg1"
|
50
|
+
Start a job to transfer a file named "file.dmg" to a local FTP server
|
104
51
|
|
105
52
|
```
|
106
53
|
curl -H "Content-Type: application/json" -X POST -D /dev/stdout -d \
|
107
|
-
'{"source":"~/file.dmg","target":"ftp://anonymous@localhost/incoming/dest4.dmg"
|
54
|
+
'{"source":"~/file.dmg","target":"ftp://anonymous@localhost/incoming/dest4.dmg"}' "http://localhost:3000/jobs"
|
108
55
|
```
|
109
56
|
|
110
|
-
|
57
|
+
Get status of a specific job based on its name
|
111
58
|
|
112
59
|
```
|
113
|
-
curl -H "Content-Type: application/json" -X
|
114
|
-
'{"source":"~/file.dmg","priority":"3", target":"ftp://anonymous@localhost/incoming/dest4.dmg","notify":"http://requestb.in/1321axg1"}' "http://localhost:3000/jobs"
|
60
|
+
curl -H "Content-Type: application/json" -X DELETE -D /dev/stdout "http://localhost:3000/jobs/bob-45320-1"
|
115
61
|
```
|
116
62
|
|
117
|
-
|
118
|
-
|
119
|
-
First define ``nas`` ans ``ftp1`` in the configuration file :
|
63
|
+
Delete a specific job based on its name
|
120
64
|
|
121
65
|
```
|
122
|
-
|
123
|
-
|
124
|
-
development:
|
125
|
-
<<: *defaults
|
126
|
-
|
127
|
-
endpoints:
|
128
|
-
nas: "~/"
|
129
|
-
ftp1: "ftp://anonymous@localhost/incoming/"
|
130
|
-
```
|
131
|
-
|
132
|
-
Thos tokens will be expanded when the job is ran :
|
133
|
-
|
134
|
-
```
|
135
|
-
curl -H "Content-Type: application/json" -X POST -D /dev/stdout -d \
|
136
|
-
'{"source":"~/file.dmg","priority":"3", target":"ftp://anonymous@localhost/incoming/dest4.dmg","notify":"http://requestb.in/1321axg1"}' "http://localhost:3000/jobs"
|
137
|
-
```
|
138
|
-
|
139
|
-
NB: a special token [RANDOM] helps to generate a random filename when needed
|
140
|
-
|
141
|
-
* Get status of a specific job based on its ID
|
142
|
-
|
143
|
-
```
|
144
|
-
curl -H "Content-Type: application/json" -X GET -D /dev/stdout "http://localhost:3000/jobs/3"
|
145
|
-
```
|
146
|
-
|
147
|
-
|
148
|
-
* Delete a specific job based on its ID
|
149
|
-
|
150
|
-
```
|
151
|
-
curl -H "Content-Type: application/json" -X DELETE -D /dev/stdout "http://localhost:3000/jobs/3"
|
66
|
+
curl -H "Content-Type: application/json" -X DELETE -D /dev/stdout "http://localhost:3000/jobs/bob-45320-1"
|
152
67
|
```
|
153
68
|
|
154
69
|
|
155
70
|
Getting status
|
156
71
|
------------------------------------------------------------------------------------
|
157
72
|
|
158
|
-
|
159
|
-
|
160
|
-
* A nice dashboard gives a global view of the daemon, jobs in queue, and system status, exposed on ``` GET /```
|
161
|
-
|
162
|
-
* The server exposes its jobs list on ``` GET /jobs ```
|
73
|
+
The server exposes jobs list on ``` GET /jobs ```
|
163
74
|
|
164
75
|
```
|
165
76
|
http://localhost:3000/jobs
|
@@ -184,19 +95,18 @@ This query will return a job list :
|
|
184
95
|
"transferred": 37100000
|
185
96
|
},
|
186
97
|
{
|
187
|
-
source: "
|
188
|
-
target: "
|
189
|
-
|
190
|
-
|
191
|
-
id:
|
192
|
-
|
193
|
-
status: "uploading",
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
file_sent: 1800000
|
98
|
+
"source": "~/file.ova",
|
99
|
+
"target": "ftp://anonymous@localhost/incoming/dest2.ova",
|
100
|
+
"worker_name": "bob-92439-2",
|
101
|
+
"created": "2014-08-01 16:53:12 +0200",
|
102
|
+
"id": 17,
|
103
|
+
"runtime": 13.8,
|
104
|
+
"status": "uploading",
|
105
|
+
"source_size": 1849036800,
|
106
|
+
"error": -1,
|
107
|
+
"errmsg": "uploading",
|
108
|
+
"progress": 36.1,
|
109
|
+
"transferred": 668300000
|
200
110
|
}
|
201
111
|
]
|
202
112
|
```
|
data/Rakefile
CHANGED
@@ -1,3 +1,51 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
|
3
3
|
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
|
17
|
+
gem.name = "rest-ftp-daemon"
|
18
|
+
gem.homepage = "http://github.com/bmedici/rest-ftp-daemon"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = "RESTful FTP client daemon"
|
21
|
+
gem.description = "This is a pretty simple FTP client daemon, controlled through a RESTfull API"
|
22
|
+
gem.email = "rest-ftp-daemon@bmconseil.com"
|
23
|
+
gem.authors = ["Bruno"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Code coverage detail"
|
36
|
+
task :simplecov do
|
37
|
+
ENV['COVERAGE'] = "true"
|
38
|
+
Rake::Task['test'].execute
|
39
|
+
end
|
40
|
+
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'rdoc/task'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "rest-ftp-daemon #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.9.0
|
data/bin/rest-ftp-daemon
CHANGED
@@ -1,42 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
# Libs and init
|
4
|
-
require
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
require 'thin'
|
5
|
+
|
6
|
+
# Initialize some local constants
|
7
|
+
APP_ROOT = File.dirname(__FILE__) + '/../'
|
8
|
+
APP_NAME = 'rest-ftp-daemon'
|
9
|
+
APP_VER = File.read "#{APP_ROOT}/VERSION"
|
10
|
+
APP_STARTED = Time.now
|
11
|
+
APP_DEFAULT_PORT = 3000
|
12
|
+
APP_LOGTO = "/tmp/#{APP_NAME}.log"
|
13
|
+
|
14
|
+
# Prepare thin
|
15
|
+
rackup_file = File.expand_path "#{APP_ROOT}/lib/config.ru"
|
12
16
|
argv = ARGV
|
13
|
-
argv << ["-
|
14
|
-
argv << ["-
|
15
|
-
argv << ["-
|
16
|
-
argv << ["--
|
17
|
-
|
18
|
-
# Rackup file
|
19
|
-
argv << ["-R", File.expand_path("#{HERE}/config.ru")] unless ARGV.include?("-R")
|
20
|
-
|
21
|
-
# Display compiled configuration
|
22
|
-
puts
|
23
|
-
puts "Daemon name \t #{Settings.name}"
|
24
|
-
puts "Version \t #{Settings.version}"
|
25
|
-
puts "Environment \t #{Settings.namespace}"
|
26
|
-
puts "Config file \t #{Settings.source}"
|
27
|
-
puts "Parameters \t #{argv.flatten}"
|
28
|
-
puts Settings.to_hash.to_yaml( :Indent => 4, :UseHeader => true, :UseVersion => false )
|
29
|
-
|
30
|
-
# Start Thin with this rackup configuration
|
31
|
-
puts
|
32
|
-
begin
|
33
|
-
Thin::Runner.new(argv.flatten).run!
|
34
|
-
rescue Thin::PidFileExist
|
35
|
-
puts "EXITING: daemon was already running (Thin::PidFileExist)"
|
36
|
-
rescue Thin::PidFileNotFound
|
37
|
-
puts "EXITING: daemon was not running (Thin::PidFileNotFound)"
|
38
|
-
else
|
39
|
-
puts "PROCESS ENDING"
|
40
|
-
end
|
41
|
-
|
17
|
+
argv << ["-R", rackup_file] unless ARGV.include?("-R")
|
18
|
+
argv << ["-p", APP_DEFAULT_PORT.to_s] unless ARGV.include?("-p")
|
19
|
+
argv << ["-e", "production"] unless ARGV.include?("-e")
|
20
|
+
argv << ["--stats", "/stats"] unless ARGV.include?("--stats")
|
42
21
|
|
22
|
+
Thin::Runner.new(argv.flatten).run!
|
data/lib/config.rb
ADDED
data/lib/config.ru
ADDED
data/lib/errors.rb
ADDED