rest-ftp-daemon 0.72b → 0.85.2

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.
@@ -1,13 +1,14 @@
1
1
  # Global libs
2
2
  require 'rubygems'
3
3
  require 'json'
4
- require 'securerandom'
5
4
  # require 'celluloid/autostart'
6
5
 
7
6
  # My libs
7
+ require 'rest-ftp-daemon/constants'
8
8
  require 'rest-ftp-daemon/config'
9
9
  require 'rest-ftp-daemon/exceptions'
10
10
  require 'rest-ftp-daemon/common'
11
+ require 'rest-ftp-daemon/helpers'
11
12
  require 'rest-ftp-daemon/uri'
12
13
  require 'rest-ftp-daemon/job_queue'
13
14
  require 'rest-ftp-daemon/worker_pool'
@@ -1,7 +1,5 @@
1
1
  # encoding: UTF-8
2
2
  require 'grape'
3
- SIZE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB" ]
4
-
5
3
 
6
4
  module RestFtpDaemon
7
5
  module API
@@ -45,13 +43,6 @@ module RestFtpDaemon
45
43
  # end
46
44
 
47
45
  helpers do
48
- def format_nice_bytes( number )
49
- return "Ø" if number.nil? || number.zero?
50
- index = ( Math.log( number ) / Math.log( 2 ) ).to_i / 10
51
- converted = number.to_i / ( 1024 ** index )
52
- "#{converted} #{SIZE_UNITS[index]}"
53
- end
54
-
55
46
  def api_error exception
56
47
  {
57
48
  :error => exception.class,
@@ -62,7 +53,7 @@ module RestFtpDaemon
62
53
  end
63
54
 
64
55
  def render name, values={}
65
- template = File.read("#{Settings.app_lib}/views/#{name.to_s}.haml")
56
+ template = File.read("#{APP_LIBS}/views/#{name.to_s}.haml")
66
57
  haml_engine = Haml::Engine.new(template)
67
58
  haml_engine.render(binding, values)
68
59
  end
@@ -6,22 +6,19 @@ module RestFtpDaemon
6
6
 
7
7
  ####### CLASS CONFIG
8
8
 
9
- #include RestFtpDaemon::API::Defaults
10
- #logger ActiveSupport::Logger.new Settings.logs.api, 'daily' unless Settings.logs.api.nil?
11
-
12
- params do
13
- optional :overwrite, type: Integer, default: false
14
- end
9
+ # params do
10
+ # optional :overwrite, type: Integer, default: false
11
+ # end
15
12
 
16
13
 
17
14
  ####### INITIALIZATION
18
15
 
19
16
  def initialize
20
- $last_worker_id = 0
17
+ #$last_worker_id = 0
21
18
 
22
19
  # Check that Queue and Pool are available
23
20
  raise RestFtpDaemon::MissingQueue unless defined? $queue
24
- raise RestFtpDaemon::MissingQueue unless defined? $pool
21
+ raise RestFtpDaemon::MissingPool unless defined? $pool
25
22
 
26
23
  super
27
24
  end
@@ -31,6 +28,13 @@ module RestFtpDaemon
31
28
 
32
29
  helpers do
33
30
 
31
+ def next_job_id
32
+ @@last_worker_id ||= 0
33
+ @@last_worker_id += 1
34
+ #Helpers.identifier(IDENT_JOB_BYTES)
35
+ #SecureRandom.hex(IDENT_JOB_BYTES)
36
+ end
37
+
34
38
  def threads_with_id job_id
35
39
  $threads.list.select do |thread|
36
40
  next unless thread[:job].is_a? Job
@@ -39,7 +43,7 @@ module RestFtpDaemon
39
43
  end
40
44
 
41
45
  def job_describe job_id
42
- raise RestFtpDaemon::JobNotFound if ($queue.queued_size==0 && $queue.popped_size==0)
46
+ raise RestFtpDaemon::JobNotFound if ($queue.all_size==0)
43
47
 
44
48
  # Find job with this id
45
49
  found = $queue.all.select { |job| job.id == job_id }.first
@@ -136,18 +140,16 @@ module RestFtpDaemon
136
140
  begin
137
141
  # Extract params
138
142
  request.body.rewind
139
- params = JSON.parse request.body.read
143
+ params = JSON.parse(request.body.read, symbolize_names: true)
140
144
 
141
145
  # Create a new job
142
- job_id = $last_worker_id += 1
146
+ # job_id = $last_worker_id += 1
147
+ job_id = next_job_id
143
148
  job = Job.new(job_id, params)
144
149
 
145
- # And psuh it to the queue
150
+ # And push it to the queue
146
151
  $queue.push job
147
152
 
148
- # Later: start it asynchronously
149
- #job.future.process
150
-
151
153
  rescue JSON::ParserError => exception
152
154
  status 406
153
155
  api_error exception
@@ -165,9 +167,9 @@ module RestFtpDaemon
165
167
 
166
168
  protected
167
169
 
168
- def progname
169
- "API::Jobs"
170
- end
170
+ # def progname
171
+ # "API::Jobs"
172
+ # end
171
173
 
172
174
  end
173
175
  end
@@ -10,11 +10,11 @@ module RestFtpDaemon
10
10
 
11
11
 
12
12
  ####### CLASS CONFIG
13
- include RestFtpDaemon::API::Defaults
14
- logger ActiveSupport::Logger.new(Settings.logs.api, 'daily') unless Settings.logs.api.nil?
15
- #add_swagger_documentation
16
13
 
14
+ include RestFtpDaemon::API::Defaults
15
+ logger RestFtpDaemon::Logger.new(:api, "API")
17
16
  mount RestFtpDaemon::API::Jobs => '/jobs'
17
+ #add_swagger_documentation
18
18
  # mount RestFtpDaemon::API::Workers => '/workers'
19
19
 
20
20
 
@@ -22,7 +22,7 @@ module RestFtpDaemon
22
22
 
23
23
  helpers do
24
24
  def info message, level = 0
25
- Root.logger.add(Logger::INFO, "#{' '*level} #{message}", "API::Root")
25
+ Root.logger.info(message, level)
26
26
  end
27
27
 
28
28
  def job_list_by_status
@@ -32,7 +32,6 @@ module RestFtpDaemon
32
32
  statuses[item.get_status] ||= 0
33
33
  statuses[item.get_status] +=1
34
34
  end
35
-
36
35
  statuses
37
36
  end
38
37
 
@@ -42,12 +41,9 @@ module RestFtpDaemon
42
41
  ####### INITIALIZATION
43
42
 
44
43
  def initialize
45
- $last_worker_id = 0
46
-
47
44
  # Check that Queue and Pool are available
48
45
  raise RestFtpDaemon::MissingQueue unless defined? $queue
49
46
  raise RestFtpDaemon::MissingQueue unless defined? $pool
50
-
51
47
  super
52
48
  end
53
49
 
@@ -56,10 +52,7 @@ module RestFtpDaemon
56
52
 
57
53
  # Server global status
58
54
  get '/' do
59
- # Prepare data
60
- @jobs_all = $queue.all
61
- #@jobs_all_size = $queue.all_size
62
- #@jobs_all = $queue.all_size
55
+ info "GET /"
63
56
 
64
57
  # Initialize UsageWatch
65
58
  Facter.loadfacts
@@ -68,24 +61,42 @@ module RestFtpDaemon
68
61
  @info_ipaddr = Facter.value(:ipaddress)
69
62
  @info_memfree = Facter.value(:memoryfree)
70
63
 
71
-
72
64
  # Compute normalized load
73
- # puts "info_procs: #{info_procs}"
74
65
  if @info_procs.zero?
75
66
  @info_norm = "N/A"
76
67
  else
77
68
  @info_norm = (100 * @info_load / @info_procs).round(1)
78
69
  end
79
70
 
80
- # Compute total transferred
81
- @total_transferred = 0
82
- @jobs_all.each do |job|
83
- sent = job.get(:file_sent)
84
- @total_transferred += sent unless sent.nil?
71
+ # Jobs to display
72
+ all_jobs_in_queue = $queue.all
73
+
74
+ if params["only"].nil? || params["only"].blank?
75
+ @only = nil
76
+ else
77
+ @only = params["only"].to_sym
85
78
  end
86
79
 
80
+ case @only
81
+ when nil
82
+ @jobs = all_jobs_in_queue
83
+ when :queue
84
+ @jobs = $queue.queued
85
+ else
86
+ @jobs = $queue.by_status (@only)
87
+ end
88
+
89
+ # Count jobs for each status
90
+ @counts = {}
91
+ grouped = all_jobs_in_queue.group_by { |job| job.get(:status) }
92
+ grouped.each do |status, jobs|
93
+ @counts[status] = jobs.size
94
+ end
95
+
96
+ # Get workers status
97
+ @gworker_statuses = $pool.get_worker_statuses
98
+
87
99
  # Compile haml template
88
- @name = "Test"
89
100
  output = render :dashboard
90
101
 
91
102
  # Send response
@@ -99,14 +110,14 @@ module RestFtpDaemon
99
110
 
100
111
  # Server global status
101
112
  get '/status' do
102
- info "GET /"
113
+ info "GET /status"
103
114
  status 200
104
115
  return {
105
116
  hostname: `hostname`.chomp,
106
- version: Settings.app_ver,
117
+ version: APP_VER,
107
118
  config: Settings.to_hash,
108
- started: Settings.app_started,
109
- uptime: (Time.now - Settings.app_started).round(1),
119
+ started: APP_STARTED,
120
+ uptime: (Time.now - APP_STARTED).round(1),
110
121
  status: job_list_by_status,
111
122
  queue_size: $queue.all_size,
112
123
  jobs_queued: $queue.queued.collect(&:id),
@@ -117,7 +128,8 @@ module RestFtpDaemon
117
128
 
118
129
  # Server test
119
130
  get '/debug' do
120
- info "GET /debug/"
131
+ info "GET /debug"
132
+
121
133
  begin
122
134
  raise RestFtpDaemon::DummyException
123
135
  rescue RestFtpDaemon::RestFtpDaemonException => exception
@@ -4,45 +4,10 @@ module RestFtpDaemon
4
4
 
5
5
  protected
6
6
 
7
- def initialize
8
- # Logger
9
- @logger = ActiveSupport::Logger.new Settings.logs.workers, 'daily' unless Settings.logs.workers.nil?
10
- end
11
-
12
- def id
13
- end
14
-
15
- def progname
16
- end
7
+ # FIXME: should be moved to class itself to get rid of this parent class
17
8
 
18
9
  def info message, level = 0
19
- # progname = "Job [#{id}]" unless id.nil?
20
- # progname = "Worker [#{id}]" unless worker_id.nil?
21
- @logger.add(Logger::INFO, "#{' '*(level+1)} #{message}", progname) unless @logger.nil?
22
- end
23
-
24
- def notify signal, error = 0, status = {}
25
- # Skip is not callback URL defined
26
- url = get :notify
27
- if url.nil?
28
- info "Skipping notification (no valid url provided) sig[#{signal}] e[#{error}] s#{status.inspect}"
29
- return
30
- end
31
-
32
- # Build notification
33
- n = RestFtpDaemon::Notification.new
34
- n.job_id = id
35
- n.url = url
36
- n.signal = signal
37
- n.error = error.inspect
38
- n.status = status
39
-
40
- # Now, send the notification
41
- info "Queuing notification key[#{n.key}] sig[#{signal}] url[#{url}]"
42
- Thread.new(n) do |thread|
43
- n.notify
44
- end
45
-
10
+ @logger.info(message, level) unless @logger.nil?
46
11
  end
47
12
 
48
13
  end
@@ -1,26 +1,21 @@
1
- require 'settingslogic'
2
-
3
- # Terrific assertions
4
- #raise "config.rb: APP_ROOT is not defined" unless defined? APP_ROOT
5
- APP_NAME = "rest-ftp-daemon"
6
- APP_CONF = "/etc/#{APP_NAME}.yml"
7
- APP_DEV = ARGV.include?("development") ? true : false
1
+ # Try to load Settingslogic
2
+ begin
3
+ require "settingslogic"
4
+ rescue LoadError
5
+ raise "config.rb warning: Settingslogic is needed to provide configuration values to the Gemspec file"
6
+ end
8
7
 
8
+ # Configuration class
9
9
  class Settings < Settingslogic
10
10
  # Read configuration
11
- source (File.exists? APP_CONF) ? APP_CONF : Hash.new
12
- namespace (APP_DEV ? "development" : "production")
11
+ namespace (defined?(APP_ENV) ? APP_ENV : "production")
12
+ source ((File.exists? APP_CONF) ? APP_CONF : Hash.new)
13
13
  suppress_errors true
14
14
 
15
- # Some constants
16
- self[:dev] = APP_DEV
17
- self[:app_name] = APP_NAME
18
- self[:app_lib] = File.expand_path File.dirname(__FILE__)
19
- self[:app_ver] = "0.72b"
20
- self[:app_started] = Time.now
21
- self[:default_trim_progname] = "18"
15
+ # Compute my PID filename
16
+ def pidfile
17
+ self["pidfile"] || "/tmp/#{APP_NAME}.port#{self['port'].to_s}.pid"
18
+ end
22
19
 
23
- # Some defaults
24
- self[:default_chunk_size] = "1000000"
25
- self[:default_notify_size] = "10000000"
26
20
  end
21
+
@@ -0,0 +1,21 @@
1
+ # Terrific constants
2
+ APP_NAME = "rest-ftp-daemon"
3
+ APP_CONF = "/etc/#{APP_NAME}.yml"
4
+ APP_VER = "0.85.2"
5
+
6
+
7
+ # Some global constants
8
+ IDENT_NOTIF_LEN = 4
9
+ IDENT_RANDOM_LEN = 8
10
+
11
+
12
+ # Some defaults
13
+ DEFAULT_CONNECT_TIMEOUT_SEC = 30
14
+ DEFAULT_UPDATE_EVERY_KB = 2048
15
+ DEFAULT_WORKERS = 1
16
+ DEFAULT_LOGS_PROGNAME_TRIM = 9
17
+
18
+
19
+ # Initialize markers
20
+ APP_STARTED = Time.now
21
+ APP_LIBS = File.dirname(__FILE__)
@@ -1,33 +1,20 @@
1
1
  module RestFtpDaemon
2
2
 
3
- class RestFtpDaemonException < StandardError; end
4
-
5
- class DummyException < RestFtpDaemonException; end
6
-
7
- class MissingQueue < RestFtpDaemonException; end
8
- class MissingPool < RestFtpDaemonException; end
9
-
10
-
11
- class RequestSourceMissing < RestFtpDaemonException; end
12
- class RequestSourceNotFound < RestFtpDaemonException; end
13
- class RequestTargetMissing < RestFtpDaemonException; end
14
- class RequestTargetScheme < RestFtpDaemonException; end
15
-
16
- class JobPrerequisitesNotMet < RestFtpDaemonException; end
17
-
18
- class JobNotFound < RestFtpDaemonException; end
19
- class JobSourceMissing < RestFtpDaemonException; end
20
- class JobSourceNotFound < RestFtpDaemonException; end
21
- class JobTargetMissing < RestFtpDaemonException; end
22
- class JobTargetUnsupported < RestFtpDaemonException; end
23
- class JobTargetUnparseable < RestFtpDaemonException; end
24
- #class JobTargetPermission < RestFtpDaemonException; end
25
- class JobTargetFileExists < RestFtpDaemonException; end
26
- class JobPrerequisitesNotMet < RestFtpDaemonException; end
27
-
28
-
29
- class NotificationMissingUrl < RestFtpDaemonException; end
30
- class NotificationMissingSignal < RestFtpDaemonException; end
31
-
3
+ class RestFtpDaemonException < StandardError; end
4
+
5
+ class DummyException < RestFtpDaemonException; end
6
+
7
+ class MissingQueue < RestFtpDaemonException; end
8
+ class MissingPool < RestFtpDaemonException; end
9
+
10
+ class JobException < RestFtpDaemonException; end
11
+ class JobNotFound < RestFtpDaemonException; end
12
+ class JobAssertionFailed < RestFtpDaemonException; end
13
+ class JobMissingAttribute < RestFtpDaemonException; end
14
+ class JobSourceNotFound < RestFtpDaemonException; end
15
+ class JobTargetUnsupported < RestFtpDaemonException; end
16
+ class JobTargetUnparseable < RestFtpDaemonException; end
17
+ class JobTargetFileExists < RestFtpDaemonException; end
18
+ class JobTooManyOpenFiles < RestFtpDaemonException; end
32
19
 
33
20
  end
@@ -0,0 +1,55 @@
1
+ require 'securerandom'
2
+
3
+
4
+ module RestFtpDaemon
5
+ class Helpers
6
+
7
+ def self.format_bytes number, unit=""
8
+ return "&Oslash;" if number.nil? || number.zero?
9
+
10
+ units = ["", "k", "M", "G", "T", "P" ]
11
+ index = ( Math.log( number ) / Math.log( 2 ) ).to_i / 10
12
+ converted = number.to_i / ( 1024 ** index )
13
+ "#{converted} #{units[index]}#{unit}"
14
+ end
15
+
16
+ def self.identifier len
17
+ rand(36**len).to_s(36)
18
+ end
19
+ #SecureRandom.hex(IDENT_JOB_BYTES)
20
+
21
+ def self.tokenize(item)
22
+ "[#{item}]"
23
+ end
24
+
25
+ def self.local_port_used? port
26
+ ip = '0.0.0.0'
27
+ timeout = 1
28
+ begin
29
+ Timeout::timeout(timeout) do
30
+ begin
31
+ TCPSocket.new(ip, port).close
32
+ true
33
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
34
+ false
35
+ rescue Errno::EADDRNOTAVAIL
36
+ "Settings.local_port_used: Errno::EADDRNOTAVAIL"
37
+ end
38
+ end
39
+ rescue Timeout::Error
40
+ false
41
+ end
42
+ end
43
+
44
+ # def snakecase
45
+ # gsub(/::/, '/').
46
+ # gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
47
+ # gsub(/([a-z\d])([A-Z])/,'\1_\2').
48
+ # tr('-', '_').
49
+ # gsub(/\s/, '_').
50
+ # gsub(/__+/, '_').
51
+ # downcase
52
+ # end
53
+
54
+ end
55
+ end