content_server 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/backup_server +8 -20
- data/bin/content_server +8 -20
- data/bin/testing_memory +60 -0
- data/bin/testing_server +57 -0
- data/ext/run_in_background/mkrf_conf.rb +34 -0
- data/lib/content_data/content_data.rb +613 -0
- data/lib/content_data/version.rb +3 -0
- data/lib/content_data.rb +6 -0
- data/lib/content_server/backup_server.rb +65 -86
- data/lib/content_server/content_server.rb +47 -77
- data/lib/content_server/file_streamer.rb +27 -33
- data/lib/content_server/queue_copy.rb +154 -49
- data/lib/content_server/queue_indexer.rb +19 -11
- data/lib/content_server/remote_content.rb +41 -23
- data/lib/content_server/server.rb +91 -0
- data/lib/content_server/version.rb +1 -1
- data/lib/content_server.rb +0 -15
- data/lib/email/email.rb +87 -0
- data/lib/email/version.rb +3 -0
- data/lib/email.rb +4 -0
- data/lib/file_copy/copy.rb +68 -0
- data/lib/file_copy/version.rb +4 -0
- data/lib/file_copy.rb +4 -0
- data/lib/file_indexing/index_agent.rb +170 -0
- data/lib/file_indexing/indexer_patterns.rb +72 -0
- data/lib/file_indexing/version.rb +3 -0
- data/lib/file_indexing.rb +9 -0
- data/lib/file_monitoring/file_monitoring.rb +105 -0
- data/lib/file_monitoring/monitor_path.rb +304 -0
- data/lib/file_monitoring/version.rb +3 -0
- data/lib/file_monitoring.rb +29 -0
- data/lib/file_utils/file_generator/README +97 -0
- data/lib/file_utils/file_generator/file_generator.rb +156 -0
- data/lib/file_utils/file_utils.rb +260 -0
- data/lib/file_utils/version.rb +3 -0
- data/lib/file_utils.rb +4 -0
- data/lib/log/version.rb +3 -0
- data/lib/log.rb +188 -0
- data/lib/networking/tcp.rb +213 -0
- data/lib/networking/version.rb +3 -0
- data/lib/networking.rb +4 -0
- data/lib/params/version.rb +3 -0
- data/lib/params.rb +419 -0
- data/lib/process_monitoring/monitoring.rb +85 -0
- data/lib/process_monitoring/monitoring_info.rb +79 -0
- data/lib/process_monitoring/send_email.rb +40 -0
- data/lib/process_monitoring/thread_safe_hash.rb +77 -0
- data/lib/process_monitoring/version.rb +3 -0
- data/lib/process_monitoring.rb +6 -0
- data/lib/run_in_background/version.rb +3 -0
- data/lib/run_in_background.rb +432 -0
- data/lib/testing_memory/testing_memory.rb +187 -0
- data/lib/testing_server/testing_server.rb +236 -0
- data/lib/testing_server/version.rb +3 -0
- data/lib/testing_server.rb +12 -0
- data/lib/validations/index_validations.rb +106 -0
- data/lib/validations/version.rb +3 -0
- data/lib/validations.rb +4 -0
- data/spec/content_data/validations_spec.rb +113 -0
- data/spec/file_copy/copy_spec.rb +54 -0
- data/spec/file_indexing/index_agent_spec.rb +53 -0
- data/spec/networking/tcp_spec.rb +95 -0
- data/spec/validations/index_validations_spec.rb +77 -0
- data/test/content_data/content_data_test.rb +290 -0
- data/test/file_generator/file_generator_spec.rb +84 -0
- data/test/file_indexing/index_agent_test/New.txt +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libexslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libxslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/xsltproc.exe +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exslt.h +102 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltconfig.h +73 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltexports.h +140 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/libexslt.h +29 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/attributes.h +38 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/documents.h +93 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extensions.h +262 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extra.h +80 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/functions.h +78 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/imports.h +75 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/keys.h +53 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/libxslt.h +30 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/namespaces.h +68 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/numbersInternals.h +69 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/pattern.h +81 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/preproc.h +43 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/security.h +104 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/templates.h +77 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/transform.h +207 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/trio.h +216 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/triodef.h +220 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/variables.h +91 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/win32config.h +101 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xslt.h +103 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltInternals.h +1967 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltconfig.h +172 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltexports.h +142 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltlocale.h +57 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltutils.h +309 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltwin32config.h +105 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/readme.txt +22 -0
- data/test/file_indexing/index_agent_test/patterns.input +3 -0
- data/test/file_indexing/index_agent_test.rb +51 -0
- data/test/file_monitoring/file_monitoring_test/conf.yml +4 -0
- data/test/file_monitoring/file_monitoring_test/conf_win32.yml +5 -0
- data/test/file_monitoring/file_monitoring_test/log +56 -0
- data/test/file_monitoring/file_monitoring_test.rb +0 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1 +1500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.0 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.1 +500 -0
- data/test/file_monitoring/monitor_path_test.rb +153 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.0 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.1 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.0 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.1 +500 -0
- data/test/file_utils/fileutil_mksymlink_test.rb +125 -0
- data/test/file_utils/time_modification_test.rb +132 -0
- data/test/params/params_spec.rb +280 -0
- data/test/params/params_test.rb +43 -0
- data/test/run_in_background/run_in_background_test.rb +122 -0
- data/test/run_in_background/test_app +57 -0
- metadata +272 -132
- data/lib/content_server/globals.rb +0 -10
data/lib/params.rb
ADDED
@@ -0,0 +1,419 @@
|
|
1
|
+
# Author: Yaron Dror (yaron.dror.bb@gmail.com)
|
2
|
+
# Description: The file contains 'Params' module implementation.
|
3
|
+
# Notes:
|
4
|
+
# module.init should be called if user wants to override defined parameters by file or command line.
|
5
|
+
# Parameter can be defined only once.
|
6
|
+
# Parameters have to be defined before they are accessed. see examples below.
|
7
|
+
#
|
8
|
+
# Examples of definitions:
|
9
|
+
# Params.string('parameter_str', 'this is a string' ,'description_for_string')
|
10
|
+
# Params.path('parameter_path', '/Users/username/example/ect' ,'description_for_directory')
|
11
|
+
# Params.integer('parameter_int',1 , 'description_for_integer')
|
12
|
+
# Params.float('parameter_float',2.6 , 'description_for_float')
|
13
|
+
# Params.boolean('parameter_true', true, 'description_for_true')
|
14
|
+
# Params.boolean('parameter_false',false , 'description_for_false')
|
15
|
+
# Params.complex('parameter_complex', [a,b,{b=>c}], 'description for dict or list of strings.')
|
16
|
+
# Note. Parameters have to be defined before they are accessed.
|
17
|
+
#
|
18
|
+
# Examples of usages (get\set access is through the [] operator).
|
19
|
+
# local_var_of_type_string = Params['parameter_str']
|
20
|
+
# puts local_var_of_type_string # Will produce --> this is a string
|
21
|
+
# Params['parameter_float'] = 3.8
|
22
|
+
# puts Params['parameter_float'] # Will produce --> 3.8
|
23
|
+
# Params['parameter_float'] = 3
|
24
|
+
# puts Params['parameter_float'] # Will produce --> 3.0 (note the casting)
|
25
|
+
# Note. only after definition, the [] operator will work. Else an error is raised.
|
26
|
+
# Params['new_param'] = true # will raise an error, since the param was not defined yet.
|
27
|
+
# Params.boolean 'new_param', true, 'this is correct' # this is the definition.
|
28
|
+
# Params['new_param'] = false # Will set new value.
|
29
|
+
# puts Params['new_param'] # Will produce --> false
|
30
|
+
#
|
31
|
+
# Type check.
|
32
|
+
# A type check is forced both when overriding with file or command line and in [] usage.
|
33
|
+
# if parameter was defined as a Float using Params.float method (e.g. 2.6) and user
|
34
|
+
# provided an integer when overriding or when using [] operator then the integer will
|
35
|
+
# be casted to float.
|
36
|
+
#
|
37
|
+
# Params.Init - override parameters.
|
38
|
+
# implementation of the init sequence allows the override of
|
39
|
+
# defined parameters with new values through input file and\or command line args.
|
40
|
+
# Note that only defined parameters can be overridden. If new parameter is parsed
|
41
|
+
# through file\command line, then an error will be raised.
|
42
|
+
# Input config file override:
|
43
|
+
# Default configuration input file path is: '~/.bbfs/conf/<executable name>.conf'
|
44
|
+
# This path can be overridden by the command line arguments (see ahead).
|
45
|
+
# If path and file exist then the parameters in the file will override the defined
|
46
|
+
# parameters. File parameters format per line:<param_name>: <param value>
|
47
|
+
# Note: Space char after the colon is mandatory
|
48
|
+
# Command line arguments override:
|
49
|
+
# General format per argument is:--<param_name>=<param_value>
|
50
|
+
# those parameters will override the defined parameters and the file parameters.
|
51
|
+
# Override input config file:
|
52
|
+
# User can override the input file by using:--conf_file=<new_file_path>
|
53
|
+
#
|
54
|
+
# More examples in bbfs/examples/params/rb
|
55
|
+
|
56
|
+
require 'optparse'
|
57
|
+
require 'stringio'
|
58
|
+
require 'yaml'
|
59
|
+
|
60
|
+
module Params
|
61
|
+
|
62
|
+
# Represents a parameter.
|
63
|
+
class Param
|
64
|
+
attr_accessor :name
|
65
|
+
attr_accessor :value
|
66
|
+
attr_accessor :desc
|
67
|
+
attr_accessor :type
|
68
|
+
|
69
|
+
# value_type_check method:
|
70
|
+
# 1. Check if member:'type' is one of:Integer, Float, String or Boolean.
|
71
|
+
# 2. input parameter:'value' class type is valid to override this parameter.
|
72
|
+
# 3. Return value. The value to override with correct type. A cast from integer to Float will
|
73
|
+
# be made for Float parameters which are set with integer values.
|
74
|
+
# 4. Check will be skipped for nil value.
|
75
|
+
def value_type_check(value)
|
76
|
+
if value.nil?
|
77
|
+
return value
|
78
|
+
end
|
79
|
+
|
80
|
+
case( @type )
|
81
|
+
when 'Integer' then
|
82
|
+
if not @value.nil?
|
83
|
+
if not ((value.class.eql? Integer) or
|
84
|
+
(value.class.eql? Fixnum))
|
85
|
+
raise "Parameter:'#{@name}' type:'Integer' but value type to override " \
|
86
|
+
"is:'#{value.class}'."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
when 'Float' then
|
90
|
+
if not @value.nil?
|
91
|
+
if not value.class.eql? Float
|
92
|
+
if not ((value.class.eql? Integer) or
|
93
|
+
(value.class.eql? Fixnum))
|
94
|
+
raise("Parameter:'#{@name}' type:'Float' but value type to override " \
|
95
|
+
"is:'#{value.class}'.")
|
96
|
+
else
|
97
|
+
return value.to_f
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
when 'String' then
|
102
|
+
when 'Path' then
|
103
|
+
# TODO(kolman): Override the type check with regexp of path in Linux and/or Windows
|
104
|
+
if not @value.nil?
|
105
|
+
if not value.class.eql? String
|
106
|
+
raise("Parameter:'#{@name}' type:'String' but value type to override " \
|
107
|
+
"is:'#{value.class}'.")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
when 'Boolean' then
|
111
|
+
if not @value.nil?
|
112
|
+
if not((value.class.eql? TrueClass) or (value.class.eql? FalseClass))
|
113
|
+
raise("Parameter:'#{@name}' type:'Boolean' but value type to override " \
|
114
|
+
"is:'#{value.class}'.")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
when 'Complex' then
|
118
|
+
unless @value.nil?
|
119
|
+
unless (value.class.eql? Hash) or (value.class.eql? Array)
|
120
|
+
raise("Parameter:'#{@name}' type:'Complex' but value type to override " \
|
121
|
+
"is:'#{value.class}'.")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
else
|
125
|
+
raise("Parameter:'#{@name}' type:'#{@value.class}' but parameter " \
|
126
|
+
"type to override:'#{value.class}' is not supported. " + \
|
127
|
+
"Supported types are:Integer, Float, String or Boolean.")
|
128
|
+
end
|
129
|
+
return value
|
130
|
+
end
|
131
|
+
|
132
|
+
# supported types are: String, Integer, Float, Boolean, Path or Complex
|
133
|
+
def initialize(name, value, type, desc)
|
134
|
+
@name = name
|
135
|
+
@type = type
|
136
|
+
@desc = desc
|
137
|
+
@value = value_type_check value
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
@params_data_base = Hash.new # The parameters data structure.
|
142
|
+
@init_info_messages = []
|
143
|
+
@show_help_and_exit = false
|
144
|
+
|
145
|
+
def Params.get_init_info_messages
|
146
|
+
return @init_info_messages
|
147
|
+
end
|
148
|
+
|
149
|
+
def Params.get_init_warning_messages
|
150
|
+
return @init_warning_messages
|
151
|
+
end
|
152
|
+
|
153
|
+
def Params.raise_error_if_param_does_not_exist(name)
|
154
|
+
if not @params_data_base[name]
|
155
|
+
raise("before using parameter:'#{name}', it should first be defined through Param module methods:" \
|
156
|
+
"Params.string, Params.path, Params.integer, Params.float, Params.complex, or Params.boolean.")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def Params.raise_error_if_param_exists(name)
|
161
|
+
if @params_data_base[name]
|
162
|
+
raise("Parameter:'#{name}', can only be defined once.")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Read param value by other modules.
|
167
|
+
# Note that this operator should only be used, after parameter has been defined through
|
168
|
+
# one of Param module methods: Params.string, Params.integer,
|
169
|
+
# Params.float or Params.boolean."
|
170
|
+
def Params.[](name)
|
171
|
+
raise_error_if_param_does_not_exist(name)
|
172
|
+
@params_data_base[name].value
|
173
|
+
end
|
174
|
+
|
175
|
+
def Params.each(&block)
|
176
|
+
@params_data_base.each(&block)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Write param value by other modules.
|
180
|
+
# Note that this operator should only be used, after parameter has been defined through
|
181
|
+
# one of Param module methods: Params.string, Params.integer,
|
182
|
+
# Params.float or Params.boolean."
|
183
|
+
def Params.[]=(name, value)
|
184
|
+
raise_error_if_param_does_not_exist(name)
|
185
|
+
set_value = @params_data_base[name].value_type_check(value)
|
186
|
+
@params_data_base[name].value = set_value
|
187
|
+
end
|
188
|
+
|
189
|
+
#override parameter should only be called by Params module methods.
|
190
|
+
def Params.override_param(name, value)
|
191
|
+
existing_param = @params_data_base[name]
|
192
|
+
if existing_param.nil?
|
193
|
+
raise("Parameter:'#{name}' has not been defined and can not be overridden. " \
|
194
|
+
"It should first be defined through Param module methods:" \
|
195
|
+
"Params.string, Params.path, Params.integer, Params.float, Params.complex, or Params.boolean.")
|
196
|
+
end
|
197
|
+
if value.nil?
|
198
|
+
existing_param.value = nil
|
199
|
+
elsif existing_param.type.eql?('String')
|
200
|
+
existing_param.value = value.to_s
|
201
|
+
elsif existing_param.type.eql?('Path')
|
202
|
+
existing_param.value = File.expand_path(value.to_s)
|
203
|
+
elsif existing_param.type.eql?('Complex')
|
204
|
+
if value.class.eql?(Hash) || value.class.eql?(Array)
|
205
|
+
existing_param.value = value
|
206
|
+
else
|
207
|
+
existing_param.value = YAML::load(StringIO.new(value.to_s))
|
208
|
+
end
|
209
|
+
else
|
210
|
+
set_value = existing_param.value_type_check(value)
|
211
|
+
existing_param.value = set_value
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Define new parameter of type Integer.
|
216
|
+
def Params.integer(name, value, description)
|
217
|
+
raise_error_if_param_exists(name)
|
218
|
+
@params_data_base[name] = Param.new(name, value, 'Integer', description)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Define new parameter of type Float.
|
222
|
+
def Params.float(name, value, description)
|
223
|
+
raise_error_if_param_exists(name)
|
224
|
+
@params_data_base[name] = Param.new(name, value, 'Float', description)
|
225
|
+
end
|
226
|
+
|
227
|
+
# Define new parameter of type String.
|
228
|
+
def Params.string(name, value, description)
|
229
|
+
raise_error_if_param_exists(name)
|
230
|
+
@params_data_base[name] = Param.new(name, value, 'String', description)
|
231
|
+
end
|
232
|
+
|
233
|
+
# Define new parameter of type path (the only difference with string is that the path expends '~' to
|
234
|
+
# full user directory).
|
235
|
+
def Params.path(name, value, description)
|
236
|
+
raise_error_if_param_exists(name)
|
237
|
+
value = File.expand_path(value) unless value.nil?
|
238
|
+
@params_data_base[name] = Param.new(name, value, 'Path', description)
|
239
|
+
end
|
240
|
+
|
241
|
+
def Params.complex(name, value, description)
|
242
|
+
raise_error_if_param_exists(name)
|
243
|
+
@params_data_base[name] = Param.new(name, value, 'Complex', description)
|
244
|
+
end
|
245
|
+
|
246
|
+
# Define new parameter of type Boolean.
|
247
|
+
def Params.boolean(name, value, description)
|
248
|
+
raise_error_if_param_exists(name)
|
249
|
+
@params_data_base[name] = Param.new(name, value, 'Boolean', description)
|
250
|
+
end
|
251
|
+
|
252
|
+
# Initializes the project parameters.
|
253
|
+
# Precedence is: Defined params, file and command line is highest.
|
254
|
+
def Params.init(args)
|
255
|
+
#define default configuration file
|
256
|
+
Params['conf_file'] = "~/.bbfs/etc/config_#{executable_name}.yml"
|
257
|
+
|
258
|
+
@init_info_messages = []
|
259
|
+
@init_warning_messages = []
|
260
|
+
|
261
|
+
#parse command line argument and set configuration file if provided by user
|
262
|
+
results = parse_command_line_arguments(args)
|
263
|
+
if results['conf_file']
|
264
|
+
Params['conf_file'] = File.expand_path(results['conf_file'])
|
265
|
+
if !File.exist?(Params['conf_file']) or File.directory?(Params['conf_file'])
|
266
|
+
raise("Param:'conf_file' value:'#{Params['conf_file']}' is a file name which does not exist" +
|
267
|
+
" or a directory name")
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
Params['conf_file'] = File.expand_path(Params['conf_file'])
|
272
|
+
|
273
|
+
#load yml params if path is provided and exists
|
274
|
+
if File.exist?(Params['conf_file'])
|
275
|
+
@init_info_messages << "Loading parameters from configuration file:'#{Params['conf_file']}'"
|
276
|
+
if not read_yml_params(File.open(Params['conf_file'], 'r'))
|
277
|
+
raise("Bad configuration file #{Params['conf_file']}.")
|
278
|
+
end
|
279
|
+
else
|
280
|
+
@init_warning_messages << "Configuration file path:'#{Params['conf_file']}' does not exist. " + \
|
281
|
+
"Skipping loading file parameters."
|
282
|
+
end
|
283
|
+
|
284
|
+
#override command line argument
|
285
|
+
results.keys.each do |result_name|
|
286
|
+
override_param(result_name, results[result_name])
|
287
|
+
end
|
288
|
+
|
289
|
+
# Prints help and parameters if needed.
|
290
|
+
if @show_help_and_exit
|
291
|
+
# Print parameters + description and exit.
|
292
|
+
puts "Full list of parameters:"
|
293
|
+
Params.each do |name, param|
|
294
|
+
puts "--#{name}, #{param.type}, default:#{param.value}\n\t#{param.desc}"
|
295
|
+
end
|
296
|
+
exit
|
297
|
+
end
|
298
|
+
|
299
|
+
# Add parameters to log init messages (used by Log.init if param:print_params_to_stdout is true)
|
300
|
+
@init_info_messages << 'Initialized executable parameters:'
|
301
|
+
@init_info_messages << '---------------------------------'
|
302
|
+
counter=0
|
303
|
+
@params_data_base.values.each do |param|
|
304
|
+
counter += 1
|
305
|
+
@init_info_messages << "Param ##{counter}: #{param.name}=#{param.value}"
|
306
|
+
end
|
307
|
+
@init_info_messages << '---------------------------------'
|
308
|
+
end
|
309
|
+
|
310
|
+
# Load yml params and override default values.
|
311
|
+
# raise exception if a loaded yml param does not exist. or if types mismatch occurs.
|
312
|
+
def Params.read_yml_params(yml_input_io)
|
313
|
+
proj_params = YAML::load(yml_input_io)
|
314
|
+
return false unless proj_params.is_a?(Hash)
|
315
|
+
proj_params.keys.each do |param_name|
|
316
|
+
override_param(param_name, proj_params[param_name])
|
317
|
+
end
|
318
|
+
true
|
319
|
+
end
|
320
|
+
|
321
|
+
# Parse command line arguments
|
322
|
+
def Params.parse_command_line_arguments(args)
|
323
|
+
results = Hash.new # Hash to store parsing results.
|
324
|
+
options = Hash.new # Hash of parsing options from Params.
|
325
|
+
|
326
|
+
# Define options switch for parsing
|
327
|
+
# Define List of options see example on
|
328
|
+
# http://ruby.about.com/od/advancedruby/a/optionparser2.htm
|
329
|
+
opts = OptionParser.new do |opts|
|
330
|
+
@params_data_base.values.each do |param|
|
331
|
+
tmp_name_long = "--#{param.name} #{param.name.upcase}" # Define a command with single mandatory parameter
|
332
|
+
tmp_value = param.desc + " Default value:" + param.value.to_s # Description and Default value
|
333
|
+
|
334
|
+
# Define type of the mandatory value
|
335
|
+
# It can be integer, float or String(for all other types).
|
336
|
+
case(param.type)
|
337
|
+
when 'Integer' then value_type = Integer
|
338
|
+
when 'Float' then value_type = Float
|
339
|
+
else value_type = String
|
340
|
+
end
|
341
|
+
# Switches definition - according to what
|
342
|
+
# was pre-defined in the Params
|
343
|
+
opts.on(tmp_name_long, value_type, tmp_value) do |result|
|
344
|
+
if result.to_s.upcase.eql? 'TRUE'
|
345
|
+
results[param.name] = true
|
346
|
+
elsif result.to_s.upcase.eql? 'FALSE'
|
347
|
+
results[param.name] = false
|
348
|
+
else
|
349
|
+
results[param.name] = result
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
# Define introduction text for help command
|
355
|
+
opts.banner =
|
356
|
+
"Usage: content_serve [options] or \n" +
|
357
|
+
" : backup_server [options] \n\n" +
|
358
|
+
"Description: This application for backuping files and folders\n" +
|
359
|
+
"There is two application: \n" +
|
360
|
+
"backup_server is server run on machine where files is backuped,\n" +
|
361
|
+
"content_server is application that run on machine from where files is copied.\n\n" +
|
362
|
+
"Before run applications:" +
|
363
|
+
"Before running backup_server and content server you need to prepare two configuration files\n" +
|
364
|
+
"Create configuration file for content server which should be located at ~/.bbfs/etc/file_monitoring.yml\n" +
|
365
|
+
"the content of the file is:
|
366
|
+
------- begin of file_monitoring.yml --------
|
367
|
+
paths:
|
368
|
+
- path: ~/.bbfs/test_files # <=== replace with your local dir.
|
369
|
+
scan_period: 1
|
370
|
+
stable_state: 5
|
371
|
+
------- end of file_monitoring.yml --------\n" +
|
372
|
+
"Create configuration file for backup server which should be located at \n" +
|
373
|
+
"~/.bbfs/etc/backup_file_monitoring.yml\n" +
|
374
|
+
"File content:
|
375
|
+
------- begin of backup_file_monitoring.yml --------
|
376
|
+
paths:
|
377
|
+
- path: ~/.bbfs/backup_data # <=== replace with your local dir.
|
378
|
+
scan_period: 1
|
379
|
+
stable_state: 5
|
380
|
+
------- end of backup_file_monitoring.yml --------\n\n" +
|
381
|
+
"Explanation about file_monitoring.yml and backup_file_monitoring.yml configuration files:
|
382
|
+
|
383
|
+
\"path:\" - say to program which folder to scan recursively in order to find new/changed files and folders.
|
384
|
+
\"scan_period:\" - how much time in seconds passed before two consecutive scans for files and directories.
|
385
|
+
\"stable_state:\" - how many scan_period passed until the file is considered stable.\n\n" +
|
386
|
+
"List of options:"
|
387
|
+
|
388
|
+
|
389
|
+
# Define help command for available options
|
390
|
+
# executing --help will printout all pre-defined switch options
|
391
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
392
|
+
@show_help_and_exit = true
|
393
|
+
end
|
394
|
+
|
395
|
+
opts.parse(args) # Parse command line
|
396
|
+
end
|
397
|
+
return results
|
398
|
+
end # end of Parse function
|
399
|
+
|
400
|
+
def Params.to_simple_hash
|
401
|
+
@params_data_base.map { |param|
|
402
|
+
param.value
|
403
|
+
}
|
404
|
+
end
|
405
|
+
|
406
|
+
#Auxiliary method to retrieve the executable name
|
407
|
+
def Params.executable_name
|
408
|
+
/([a-zA-Z0-9\-_\.]+):\d+/ =~ caller[caller.size-1]
|
409
|
+
return $1
|
410
|
+
end
|
411
|
+
|
412
|
+
Params.path('conf_file', nil, 'Configuration file path.')
|
413
|
+
Params.boolean('print_params_to_stdout', false, 'print_params_to_stdout or not during Params.init')
|
414
|
+
|
415
|
+
private_class_method :parse_command_line_arguments, \
|
416
|
+
:raise_error_if_param_exists, :raise_error_if_param_does_not_exist, \
|
417
|
+
:read_yml_params, :override_param, :executable_name
|
418
|
+
end
|
419
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
require 'log'
|
4
|
+
require 'params'
|
5
|
+
|
6
|
+
require 'process_monitoring/send_email'
|
7
|
+
|
8
|
+
# This module purpose it to alert the user on different behaviour such as no space left
|
9
|
+
# or other error cases. The module will send email to the user to notify him on those cases.
|
10
|
+
module Monitoring
|
11
|
+
Params.float('monitoring_sleep_time_in_seconds', 10,
|
12
|
+
'Represents the monitoring sleeping time in seconds to check data')
|
13
|
+
Params.float('send_email_duration_4_monitoring_state', 60*60, # Once per hour.
|
14
|
+
'Represents the duration in seconds to send email monitoring state')
|
15
|
+
|
16
|
+
# Username and Password for gmail account to send monitoting emails.
|
17
|
+
Params.string('gmail_username', nil, 'Backup server gmail username.')
|
18
|
+
Params.string('gmail_password', nil, 'Backup server gmail password.')
|
19
|
+
|
20
|
+
class Monitoring
|
21
|
+
attr_reader :thread
|
22
|
+
def initialize(process_variables)
|
23
|
+
@thread = 'dummy'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
=begin
|
27
|
+
class Monitoring < Log::Consumer
|
28
|
+
attr_reader :thread
|
29
|
+
def initialize(process_variables)
|
30
|
+
super(false)
|
31
|
+
@passed_time_dur = 0
|
32
|
+
@process_variables = process_variables
|
33
|
+
@thread = Thread.new do
|
34
|
+
loop do
|
35
|
+
Log.debug3 'Sleeping in process monitoring.'
|
36
|
+
sleep(Params['monitoring_sleep_time_in_seconds'])
|
37
|
+
Log.debug3 'Awake in process monitoring.'
|
38
|
+
@passed_time_dur += Params['monitoring_sleep_time_in_seconds']
|
39
|
+
Log.debug3 'handle_logs in process monitoring.'
|
40
|
+
handle_logs()
|
41
|
+
Log.debug3 'handle_monitoring_state in process monitoring.'
|
42
|
+
handle_monitoring_state()
|
43
|
+
@process_variables.inc('monitoring_loop_count')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
# For debug purposes.
|
47
|
+
@thread.abort_on_exception = true
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
# To keep thread safe state all methods should be private and executed only from @thread
|
52
|
+
def send_email(subject, body)
|
53
|
+
SendEmail.send_email({
|
54
|
+
:to => Params['gmail_username'],
|
55
|
+
:from => Params['gmail_username'],
|
56
|
+
:password => Params['gmail_password'],
|
57
|
+
:body => body,
|
58
|
+
:subject => subject,
|
59
|
+
})
|
60
|
+
end
|
61
|
+
|
62
|
+
# Override logs consumer handler.
|
63
|
+
def handle_logs
|
64
|
+
while log_msg = @consumer_queue.pop(non_block=true) do
|
65
|
+
send_log_email(log_msg) if Log.is_error(log_msg)
|
66
|
+
end rescue ThreadError # Rescue when queue is empty.
|
67
|
+
end
|
68
|
+
|
69
|
+
def handle_monitoring_state
|
70
|
+
if @passed_time_dur > Params['send_email_duration_4_monitoring_state']
|
71
|
+
send_email('BBFS Current Monitoring State notification', get_monitoring_state_body())
|
72
|
+
@passed_time_dur = 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_monitoring_state_body
|
77
|
+
# TODO(slava): Implement the following function.
|
78
|
+
# MonitoringInfo::MonitoringInfo.get_html(@process_variables)
|
79
|
+
"server_name: #{@process_variables.get('server_name')}\n" +
|
80
|
+
"num_files_received: #{@process_variables.get('num_files_received')}\n" +
|
81
|
+
"monitoring_loop_count: #{@process_variables.get('monitoring_loop_count')}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
=end
|
85
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'json'
|
3
|
+
require 'net/http'
|
4
|
+
require 'thin'
|
5
|
+
require 'sinatra'
|
6
|
+
|
7
|
+
require 'content_server/server'
|
8
|
+
require 'params'
|
9
|
+
|
10
|
+
# Set up event machine to exit on ctrl+c.
|
11
|
+
EventMachine.schedule do
|
12
|
+
trap("INT") do
|
13
|
+
puts "Caught SIGINT"
|
14
|
+
# EventMachine.stop # this is useless
|
15
|
+
exit # exit # this stops the EventMachine
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# This module export process info to http port, that way the user may access with the
|
20
|
+
# browser to the process to see what is happening inside, what is it's state and parameters.
|
21
|
+
module MonitoringInfo
|
22
|
+
|
23
|
+
Params.integer('process_monitoring_web_port', 5555,
|
24
|
+
'The port from which monitoring data will be served as http.')
|
25
|
+
|
26
|
+
class MonitoringInfo
|
27
|
+
attr_reader :thread
|
28
|
+
|
29
|
+
def initialize()
|
30
|
+
@web_interface = Sinatra.new {
|
31
|
+
set :bind, '0.0.0.0'
|
32
|
+
get('/') { MonitoringInfo.get_json($process_vars.clone) }
|
33
|
+
}
|
34
|
+
@web_interface.set(:port, Params['process_monitoring_web_port'])
|
35
|
+
@thread = Thread.new do
|
36
|
+
@web_interface.run!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.get_json(hash)
|
41
|
+
return '' if !hash.is_a?(Hash)
|
42
|
+
|
43
|
+
entries = []
|
44
|
+
hash.each do |key, value|
|
45
|
+
entries << "{#{key}:#{value}}"
|
46
|
+
end
|
47
|
+
|
48
|
+
return entries.join(" , ")
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.get_html (hash, opts = {})
|
52
|
+
return if !hash.is_a?(Hash)
|
53
|
+
|
54
|
+
indent_level = opts.fetch(:indent_level) { 0 }
|
55
|
+
|
56
|
+
out = " " * indent_level + "<ul>\n"
|
57
|
+
|
58
|
+
hash.each do |key, value|
|
59
|
+
out += " " * (indent_level + 2) + "<li><strong>#{key}:</strong>"
|
60
|
+
|
61
|
+
if value.is_a?(Hash)
|
62
|
+
out += "\n" + get_html(value, :indent_level => indent_level + 2) + " " * (indent_level + 2) + "</li>\n"
|
63
|
+
else
|
64
|
+
out += " <span>#{value}</span></li>\n"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
out += " " * indent_level + "</ul>\n"
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.get_remote_monitoring_info(host, port)
|
72
|
+
begin
|
73
|
+
JSON.parse(Net::HTTP.get(URI("http://#{host}:#{port}/")))
|
74
|
+
rescue Errno::ECONNREFUSED => e
|
75
|
+
''
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
require 'log'
|
4
|
+
require 'params'
|
5
|
+
|
6
|
+
module SendEmail
|
7
|
+
Params.boolean('enable_monitoring_emails', false, 'Whether to send emails for process monitoring events.')
|
8
|
+
|
9
|
+
#class SendEmail
|
10
|
+
def SendEmail.send_email(opts={})
|
11
|
+
opts[:to] ||= '' # Required.
|
12
|
+
opts[:from] ||= '' # Required.
|
13
|
+
opts[:from_alias] ||= 'BBFS Monitoring'
|
14
|
+
opts[:subject] ||= 'BBFS Notification subject'
|
15
|
+
opts[:body] ||= 'BBFS Body'
|
16
|
+
opts[:password] ||= '' # Required.
|
17
|
+
|
18
|
+
msg = "From: #{opts[:from_alias]} <#{opts[:from]}>\n" \
|
19
|
+
"To: <#{opts[:to]}>\n" \
|
20
|
+
"Subject: #{opts[:subject]}\n" \
|
21
|
+
"#{opts[:body]}"
|
22
|
+
|
23
|
+
email_log_message = "Send actual email: #{Params['enable_monitoring_emails']}.\n" \
|
24
|
+
"to: #{opts[:to]}\n" \
|
25
|
+
"msg:#{msg}"
|
26
|
+
if Params['enable_monitoring_emails']
|
27
|
+
Log.debug1(email_log_message)
|
28
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
29
|
+
smtp.enable_starttls
|
30
|
+
smtp.start('bbfs.com', opts[:from], opts[:password], :login) do
|
31
|
+
smtp.send_message(msg, opts[:from], opts[:to])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
Log.info(email_log_message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
#end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Simple thread safe hash.
|
2
|
+
module ThreadSafeHash
|
3
|
+
class ThreadSafeHash
|
4
|
+
def initialize()
|
5
|
+
@hash_data = Hash.new()
|
6
|
+
@mutex = Mutex.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def inc(key)
|
10
|
+
@mutex.synchronize do
|
11
|
+
value = @hash_data[key]
|
12
|
+
if value.nil?
|
13
|
+
@hash_data[key] = 1
|
14
|
+
else
|
15
|
+
@hash_data[key] = value + 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def dec(key)
|
21
|
+
@mutex.synchronize do
|
22
|
+
value = @hash_data[key]
|
23
|
+
if value.nil?
|
24
|
+
@hash_data[key] = -1
|
25
|
+
else
|
26
|
+
@hash_data[key] = value - 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(key)
|
32
|
+
@mutex.synchronize do
|
33
|
+
@hash_data[key]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def set(key, value)
|
38
|
+
@mutex.synchronize do
|
39
|
+
@hash_data[key] = value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def clone
|
44
|
+
@mutex.synchronize do
|
45
|
+
@hash_data.clone
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class ThreadSafeHashMonitored < ThreadSafeHash
|
51
|
+
def initialize(monitored)
|
52
|
+
super()
|
53
|
+
@monitored = monitored
|
54
|
+
end
|
55
|
+
|
56
|
+
def inc(key)
|
57
|
+
super if @monitored
|
58
|
+
end
|
59
|
+
|
60
|
+
def dec(key)
|
61
|
+
super if @monitored
|
62
|
+
end
|
63
|
+
|
64
|
+
def get(key)
|
65
|
+
super if @monitored
|
66
|
+
end
|
67
|
+
|
68
|
+
def set(key, value)
|
69
|
+
super if @monitored
|
70
|
+
end
|
71
|
+
|
72
|
+
def clone
|
73
|
+
super if @monitored
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|