content_server 1.1.0 → 1.2.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.
Files changed (137) hide show
  1. data/bin/backup_server +8 -20
  2. data/bin/content_server +8 -20
  3. data/bin/testing_memory +60 -0
  4. data/bin/testing_server +57 -0
  5. data/ext/run_in_background/mkrf_conf.rb +34 -0
  6. data/lib/content_data/content_data.rb +613 -0
  7. data/lib/content_data/version.rb +3 -0
  8. data/lib/content_data.rb +6 -0
  9. data/lib/content_server/backup_server.rb +65 -86
  10. data/lib/content_server/content_server.rb +47 -77
  11. data/lib/content_server/file_streamer.rb +27 -33
  12. data/lib/content_server/queue_copy.rb +154 -49
  13. data/lib/content_server/queue_indexer.rb +19 -11
  14. data/lib/content_server/remote_content.rb +41 -23
  15. data/lib/content_server/server.rb +91 -0
  16. data/lib/content_server/version.rb +1 -1
  17. data/lib/content_server.rb +0 -15
  18. data/lib/email/email.rb +87 -0
  19. data/lib/email/version.rb +3 -0
  20. data/lib/email.rb +4 -0
  21. data/lib/file_copy/copy.rb +68 -0
  22. data/lib/file_copy/version.rb +4 -0
  23. data/lib/file_copy.rb +4 -0
  24. data/lib/file_indexing/index_agent.rb +170 -0
  25. data/lib/file_indexing/indexer_patterns.rb +72 -0
  26. data/lib/file_indexing/version.rb +3 -0
  27. data/lib/file_indexing.rb +9 -0
  28. data/lib/file_monitoring/file_monitoring.rb +105 -0
  29. data/lib/file_monitoring/monitor_path.rb +304 -0
  30. data/lib/file_monitoring/version.rb +3 -0
  31. data/lib/file_monitoring.rb +29 -0
  32. data/lib/file_utils/file_generator/README +97 -0
  33. data/lib/file_utils/file_generator/file_generator.rb +156 -0
  34. data/lib/file_utils/file_utils.rb +260 -0
  35. data/lib/file_utils/version.rb +3 -0
  36. data/lib/file_utils.rb +4 -0
  37. data/lib/log/version.rb +3 -0
  38. data/lib/log.rb +188 -0
  39. data/lib/networking/tcp.rb +213 -0
  40. data/lib/networking/version.rb +3 -0
  41. data/lib/networking.rb +4 -0
  42. data/lib/params/version.rb +3 -0
  43. data/lib/params.rb +419 -0
  44. data/lib/process_monitoring/monitoring.rb +85 -0
  45. data/lib/process_monitoring/monitoring_info.rb +79 -0
  46. data/lib/process_monitoring/send_email.rb +40 -0
  47. data/lib/process_monitoring/thread_safe_hash.rb +77 -0
  48. data/lib/process_monitoring/version.rb +3 -0
  49. data/lib/process_monitoring.rb +6 -0
  50. data/lib/run_in_background/version.rb +3 -0
  51. data/lib/run_in_background.rb +432 -0
  52. data/lib/testing_memory/testing_memory.rb +187 -0
  53. data/lib/testing_server/testing_server.rb +236 -0
  54. data/lib/testing_server/version.rb +3 -0
  55. data/lib/testing_server.rb +12 -0
  56. data/lib/validations/index_validations.rb +106 -0
  57. data/lib/validations/version.rb +3 -0
  58. data/lib/validations.rb +4 -0
  59. data/spec/content_data/validations_spec.rb +113 -0
  60. data/spec/file_copy/copy_spec.rb +54 -0
  61. data/spec/file_indexing/index_agent_spec.rb +53 -0
  62. data/spec/networking/tcp_spec.rb +95 -0
  63. data/spec/validations/index_validations_spec.rb +77 -0
  64. data/test/content_data/content_data_test.rb +290 -0
  65. data/test/file_generator/file_generator_spec.rb +84 -0
  66. data/test/file_indexing/index_agent_test/New.txt +0 -0
  67. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libexslt.dll +0 -0
  68. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libxslt.dll +0 -0
  69. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/xsltproc.exe +0 -0
  70. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exslt.h +102 -0
  71. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltconfig.h +73 -0
  72. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltexports.h +140 -0
  73. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/libexslt.h +29 -0
  74. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/attributes.h +38 -0
  75. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/documents.h +93 -0
  76. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extensions.h +262 -0
  77. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extra.h +80 -0
  78. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/functions.h +78 -0
  79. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/imports.h +75 -0
  80. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/keys.h +53 -0
  81. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/libxslt.h +30 -0
  82. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/namespaces.h +68 -0
  83. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/numbersInternals.h +69 -0
  84. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/pattern.h +81 -0
  85. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/preproc.h +43 -0
  86. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/security.h +104 -0
  87. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/templates.h +77 -0
  88. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/transform.h +207 -0
  89. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/trio.h +216 -0
  90. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/triodef.h +220 -0
  91. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/variables.h +91 -0
  92. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/win32config.h +101 -0
  93. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xslt.h +103 -0
  94. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltInternals.h +1967 -0
  95. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltconfig.h +172 -0
  96. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltexports.h +142 -0
  97. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltlocale.h +57 -0
  98. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltutils.h +309 -0
  99. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltwin32config.h +105 -0
  100. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt.lib +0 -0
  101. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt_a.lib +0 -0
  102. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt.lib +0 -0
  103. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt_a.lib +0 -0
  104. data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/readme.txt +22 -0
  105. data/test/file_indexing/index_agent_test/patterns.input +3 -0
  106. data/test/file_indexing/index_agent_test.rb +51 -0
  107. data/test/file_monitoring/file_monitoring_test/conf.yml +4 -0
  108. data/test/file_monitoring/file_monitoring_test/conf_win32.yml +5 -0
  109. data/test/file_monitoring/file_monitoring_test/log +56 -0
  110. data/test/file_monitoring/file_monitoring_test.rb +0 -0
  111. data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000 +1000 -0
  112. data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0 +1000 -0
  113. data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1 +1000 -0
  114. data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500 +1500 -0
  115. data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0 +1500 -0
  116. data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1 +1500 -0
  117. data/test/file_monitoring/monitor_path_test/test_file.500 +500 -0
  118. data/test/file_monitoring/monitor_path_test/test_file.500.0 +500 -0
  119. data/test/file_monitoring/monitor_path_test/test_file.500.1 +500 -0
  120. data/test/file_monitoring/monitor_path_test.rb +153 -0
  121. data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500 +1500 -0
  122. data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.0 +1500 -0
  123. data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.1 +1500 -0
  124. data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000 +1000 -0
  125. data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.0 +1000 -0
  126. data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.1 +1000 -0
  127. data/test/file_utils/fileutil_mksymlink_test/test_file.500 +500 -0
  128. data/test/file_utils/fileutil_mksymlink_test/test_file.500.0 +500 -0
  129. data/test/file_utils/fileutil_mksymlink_test/test_file.500.1 +500 -0
  130. data/test/file_utils/fileutil_mksymlink_test.rb +125 -0
  131. data/test/file_utils/time_modification_test.rb +132 -0
  132. data/test/params/params_spec.rb +280 -0
  133. data/test/params/params_test.rb +43 -0
  134. data/test/run_in_background/run_in_background_test.rb +122 -0
  135. data/test/run_in_background/test_app +57 -0
  136. metadata +272 -132
  137. 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
+