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
@@ -0,0 +1,432 @@
|
|
1
|
+
# Author: Genady Petelko (nukegluk@gmail.com)
|
2
|
+
# Description: The file contains implementation of 'RunInBackground' module.
|
3
|
+
|
4
|
+
require 'params'
|
5
|
+
require 'log'
|
6
|
+
|
7
|
+
# This library provides a basic cross-platform functionality to run arbitrary ruby scripts
|
8
|
+
# in background and control them. <br>Supported platforms: Windows, Linux, Mac
|
9
|
+
# NOTE UAC (User Account Control) should be disabled to use library on Windows 7:
|
10
|
+
# * Click on the Windows Icon
|
11
|
+
# * Click on the Control Panel
|
12
|
+
# * Type in UAC in the search box (up-right corner of your window)
|
13
|
+
# * Click on "Change User Account Control settings"
|
14
|
+
# * Drag the slider down to either "Notify me when programs try to make changes to my computer"
|
15
|
+
# or to disable it completely
|
16
|
+
# * Reboot your computer when you're ready
|
17
|
+
# == General Limitations:
|
18
|
+
# * Only ruby scripts can be run in background.
|
19
|
+
# * No multiple instances with the same name.
|
20
|
+
# == Notes:
|
21
|
+
# * Linux/Mac specific methods have _linux suffix
|
22
|
+
# * Windows specific methods have _windows suffix
|
23
|
+
# * While enhancing windows code, take care that paths are in windows format,
|
24
|
+
# <br>e.i. with "\\" file separator while ruby by default uses a "/"
|
25
|
+
# * Additional functionality such as restart, reload, etc. will be added on demand
|
26
|
+
# * Remains support to provide platform specific options for start.
|
27
|
+
# <br>For more information regarding such options
|
28
|
+
# see documentation for win32-sevice (Windows), daemons (Linux/Mac)
|
29
|
+
# == Linux Notes:
|
30
|
+
# * <tt>pid_dir</tt> parameter contains absolute path to directory where pid files will be stored.
|
31
|
+
# <br>If directory doesn't exists then it will be created.
|
32
|
+
# <br>User should have a read/write permissions to this location.
|
33
|
+
# <br>Default location: <tt>$HOME/.bbfs/pids</tt>
|
34
|
+
# * User should check that default pid directory is free from pid files of "killed" daemons.
|
35
|
+
# <br>It may happen, for example, when system finished in abnormal way then pid files were
|
36
|
+
# not deleted by daemons library.
|
37
|
+
# <br>In such case incorrect results can be received, for example for <tt>exists?</tt> method
|
38
|
+
# <br>One of the suggested methods can be before starting a daemon to check with <tt>exists?</tt>
|
39
|
+
# method whether daemon already exists and with <tt>running?</tt> method does it running.
|
40
|
+
module RunInBackground
|
41
|
+
Params.string('bg_command', nil, 'Server\'s command. Commands are: start, delete and nil for' \
|
42
|
+
' not running in background.')
|
43
|
+
Params.string('service_name', File.basename($0), 'Background service name.')
|
44
|
+
|
45
|
+
# Maximal time in seconds to wait until OS will finish a requested operation,
|
46
|
+
# e.g. daemon start/delete.
|
47
|
+
TIMEOUT = 20
|
48
|
+
|
49
|
+
if RUBY_PLATFORM =~ /linux/ or RUBY_PLATFORM =~ /darwin/
|
50
|
+
begin
|
51
|
+
require 'daemons'
|
52
|
+
require 'fileutils'
|
53
|
+
rescue LoadError
|
54
|
+
require 'rubygems'
|
55
|
+
require 'daemons'
|
56
|
+
require 'fileutils'
|
57
|
+
end
|
58
|
+
|
59
|
+
OS = :LINUX
|
60
|
+
Params.string('pid_dir', File.expand_path(File.join(Dir.home, '.bbfs', 'pids')),
|
61
|
+
'Absolute path to directory, where pid files will be stored. ' + \
|
62
|
+
'User should have a read/write permissions to this location. ' + \
|
63
|
+
'If absent then it will be created. ' + \
|
64
|
+
'It\'s actual only for Linux/Mac. ' + \
|
65
|
+
'For more information see documentation on daemons module. ' +\
|
66
|
+
'Default location is: $HOME/.bbfs/pids')
|
67
|
+
|
68
|
+
if Dir.exists? Params['pid_dir']
|
69
|
+
unless File.directory? Params['pid_dir']
|
70
|
+
raise IOError.new("pid directory #{Params['pid_dir']} should be a directory")
|
71
|
+
end
|
72
|
+
unless File.readable?(Params['pid_dir']) && File.writable?(Params['pid_dir'])
|
73
|
+
raise IOError.new("you should have read/write permissions to pid dir: #{Params['pid_dir']}")
|
74
|
+
end
|
75
|
+
else
|
76
|
+
::FileUtils.mkdir_p Params['pid_dir']
|
77
|
+
end
|
78
|
+
elsif RUBY_PLATFORM =~ /mingw/ or RUBY_PLATFORM =~ /ms/ or RUBY_PLATFORM =~ /win/
|
79
|
+
require 'rbconfig'
|
80
|
+
begin
|
81
|
+
require 'win32/service'
|
82
|
+
require 'win32/daemon'
|
83
|
+
rescue LoadError
|
84
|
+
require 'rubygems'
|
85
|
+
require 'win32/service'
|
86
|
+
require 'win32/daemon'
|
87
|
+
end
|
88
|
+
include Win32
|
89
|
+
|
90
|
+
OS = :WINDOWS
|
91
|
+
# Get ruby interpreter path. Need it to run ruby binary.
|
92
|
+
# <br>TODO check whether this code works with Windows Ruby Version Management (e.g. Pik)
|
93
|
+
RUBY_INTERPRETER_PATH = File.join(Config::CONFIG["bindir"],
|
94
|
+
Config::CONFIG["RUBY_INSTALL_NAME"] +
|
95
|
+
Config::CONFIG["EXEEXT"]).tr!('/','\\')
|
96
|
+
|
97
|
+
# Path has to be absolute cause Win32-Service demands it.
|
98
|
+
wrapper = File.join(File.dirname(__FILE__), "..", "bin", File.basename(__FILE__, ".rb"), "daemon_wrapper")
|
99
|
+
# Wrapper script, that can receive commands from Windows Service Control and run user script,
|
100
|
+
# <br> provided as it's argument
|
101
|
+
WRAPPER_SCRIPT = File.expand_path(wrapper).tr!('/','\\')
|
102
|
+
else
|
103
|
+
raise "Unsupported platform #{RUBY_PLATFORM}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# Start a service/daemon.
|
107
|
+
# <br>It important to delete it after usage.
|
108
|
+
# ==== Arguments
|
109
|
+
# * <tt>binary_path</tt> - absolute path to the script that should be run in background
|
110
|
+
# NOTE for Linux script should be executable and with UNIX end-of-lines (LF).
|
111
|
+
# * <tt>binary_args</tt> - Array (not nil) of script's command line arguments
|
112
|
+
# * <tt>name</tt> - service/daemon name.
|
113
|
+
# NOTE should be unique
|
114
|
+
# * <tt>opts_specific</tt> - Hash of platform specific options (only for more specific usage)
|
115
|
+
# For more information regarding such options see documentation for
|
116
|
+
# win32-sevice (Windows), daemons (Linux/Mac)
|
117
|
+
# ==== Example (LINUX)
|
118
|
+
# <tt> RunInBackground.start "/home/user/test_app", [], "daemon_test", {:monitor => true}</tt>
|
119
|
+
def RunInBackground.start binary_path, binary_args, name, opts_specific = {}
|
120
|
+
Log.debug1("executable that should be run as daemon/service: #{binary_path}")
|
121
|
+
Log.debug1("arguments: #{binary_args}")
|
122
|
+
Log.debug1("specific options: #{opts_specific}")
|
123
|
+
|
124
|
+
if binary_path == nil or binary_args == nil or name == nil
|
125
|
+
Log.error("binary path, binary args, name arguments must be defined")
|
126
|
+
raise ArgumentError.new("binary path, binary args, name arguments must be defined")
|
127
|
+
end
|
128
|
+
|
129
|
+
if OS == :WINDOWS
|
130
|
+
new_binary_path = String.new(binary_path)
|
131
|
+
new_binary_args = Array.new(binary_args)
|
132
|
+
wrap_windows new_binary_path, new_binary_args
|
133
|
+
start_windows new_binary_path, new_binary_args, name, opts_specific
|
134
|
+
else # OS == LINUX
|
135
|
+
start_linux binary_path, binary_args, name, opts_specific
|
136
|
+
end
|
137
|
+
|
138
|
+
0.upto(TIMEOUT) do
|
139
|
+
if exists?(name) && running?(name)
|
140
|
+
puts "daemon/service #{name} started\n"
|
141
|
+
Log.debug1("daemon/service #{name} started")
|
142
|
+
return
|
143
|
+
end
|
144
|
+
sleep 1
|
145
|
+
end
|
146
|
+
# if got here then something gone wrong and daemon/service wasn't started in timely manner
|
147
|
+
delete name if exists? name
|
148
|
+
Log.error("daemon/service #{name} wasn't started in timely manner")
|
149
|
+
Log.flush
|
150
|
+
raise "daemon/service #{name} wasn't started in timely manner"
|
151
|
+
end
|
152
|
+
|
153
|
+
def RunInBackground.start_linux binary_path, binary_args, name, opts = {}
|
154
|
+
unless File.executable? binary_path
|
155
|
+
raise ArgumentError.new("#{binary_path} is not executable.")
|
156
|
+
end
|
157
|
+
|
158
|
+
if opts.has_key? :dir
|
159
|
+
raise ArgumentError.new("No support for user-defined pid directories. See help")
|
160
|
+
end
|
161
|
+
|
162
|
+
opts[:app_name] = name
|
163
|
+
opts[:ARGV] = ['start']
|
164
|
+
(opts[:ARGV] << '--').concat(binary_args) if !binary_args.nil? && binary_args.size > 0
|
165
|
+
opts[:dir] = Params['pid_dir']
|
166
|
+
opts[:dir_mode] = :normal
|
167
|
+
|
168
|
+
Log.debug1("binary path: #{binary_path}")
|
169
|
+
Log.debug1("opts: #{opts}")
|
170
|
+
|
171
|
+
# Current process, that creates daemon, will transfer control to the Daemons library.
|
172
|
+
# So to continue working with current process, daemon creation initiated from separate process.
|
173
|
+
pid = fork do
|
174
|
+
Daemons.run binary_path, opts
|
175
|
+
end
|
176
|
+
Process.waitpid pid
|
177
|
+
end
|
178
|
+
|
179
|
+
def RunInBackground.start_windows binary_path, binary_args, name, opts = {}
|
180
|
+
raise ArgumentError.new("#{binary_path} doesn't exist'") unless File.exists? binary_path
|
181
|
+
|
182
|
+
# path that contains spaces must be escaped to be interpreted correctly
|
183
|
+
binary_path = %Q{"#{binary_path}"} if binary_path =~ / /
|
184
|
+
binary_path.tr!('/','\\')
|
185
|
+
# service should be run with the same load path as a current application
|
186
|
+
load_path = get_load_path
|
187
|
+
binary_args_str = binary_args.join ' '
|
188
|
+
|
189
|
+
opts[:binary_path_name] = \
|
190
|
+
"#{RUBY_INTERPRETER_PATH} #{load_path} #{binary_path} #{binary_args_str}"
|
191
|
+
# quotation marks must be escaped cause of ARGV parsing
|
192
|
+
opts[:binary_path_name] = opts[:binary_path_name].gsub '"', '"\\"'
|
193
|
+
opts[:service_name] = name
|
194
|
+
opts[:description] = name unless opts.has_key? :description
|
195
|
+
opts[:display_name] = name unless opts.has_key? :display_name
|
196
|
+
opts[:service_type] = Service::WIN32_OWN_PROCESS unless opts.has_key? :service_type
|
197
|
+
opts[:start_type] = Service::DEMAND_START unless opts.has_key? :start_type
|
198
|
+
|
199
|
+
# NOTE most of examples uses these dependencies. Meanwhile no explanations were found
|
200
|
+
opts[:dependencies] = ['W32Time','Schedule'] unless opts.has_key? :dependencies
|
201
|
+
# NOTE most of examples uses this option as defined beneath. The default is nil.
|
202
|
+
#opts[:load_order_group] = 'Network' unless opts.has_key? :load_order_group
|
203
|
+
|
204
|
+
Log.debug1("create service options: #{opts}")
|
205
|
+
Service.create(opts)
|
206
|
+
begin
|
207
|
+
Service.start(opts[:service_name])
|
208
|
+
rescue
|
209
|
+
Service.delete(opts[:service_name]) if Service.exists?(opts[:service_name])
|
210
|
+
raise
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Rerun current script in background.
|
215
|
+
# <br>Current process will be closed.
|
216
|
+
# <br>It suggested to remove from ARGV any command line arguments that point
|
217
|
+
# to run script in background, <br>otherwise an unexpexted result can be received
|
218
|
+
def RunInBackground.start! name, opts = {}
|
219
|
+
# $0 is the executable name.
|
220
|
+
start(File.expand_path($0), ARGV, name, opts)
|
221
|
+
Log.flush
|
222
|
+
exit!
|
223
|
+
end
|
224
|
+
|
225
|
+
# Run in background script that was written as Windows Service, i.e. can receive signals
|
226
|
+
# from Service Control.
|
227
|
+
# <br>The code that is run in this script should be an extension of Win32::Daemon class.
|
228
|
+
# <br>For more information see Win32::Daemon help and examples.
|
229
|
+
# <br>No need to wrap such a script.
|
230
|
+
def RunInBackground.start_win32service binary_path, binary_args, name, opts_specific = {}
|
231
|
+
Log.debug1("executable that should be run as service: #{binary_path}")
|
232
|
+
Log.debug1("arguments: #{binary_args}")
|
233
|
+
Log.debug1("specific options: #{opts_specific}")
|
234
|
+
|
235
|
+
if OS == :WINDOWS
|
236
|
+
start_windows binary_path, binary_args, name, opts_specific
|
237
|
+
else # OS == :LINUX
|
238
|
+
raise NotImplementedError.new("Unsupported method on #{OS}")
|
239
|
+
end
|
240
|
+
0.upto(TIMEOUT) do
|
241
|
+
if exists?(name) && running?(name)
|
242
|
+
puts "windows service #{name} started\n"
|
243
|
+
Log.debug1("windows service #{name} started")
|
244
|
+
return
|
245
|
+
end
|
246
|
+
sleep 1
|
247
|
+
end
|
248
|
+
# if got here then something gone wrong and daemon/service wasn't started in timely manner
|
249
|
+
delete name if exists? name
|
250
|
+
Log.error("daemon/service #{name} wasn't started in timely manner")
|
251
|
+
Log.flush
|
252
|
+
raise "daemon/service #{name} wasn't started in timely manner"
|
253
|
+
end
|
254
|
+
|
255
|
+
# Wrap an arbitrary ruby script withing script that can be run as Windows Service.
|
256
|
+
# ==== Arguments
|
257
|
+
# * <tt>binary_path</tt> - absolute path of the script that should be run in background
|
258
|
+
# * <tt>binary_args</tt> - array (not nil) of scripts command line arguments
|
259
|
+
#
|
260
|
+
# NOTE binary_path and binary_args contents will be change
|
261
|
+
def RunInBackground.wrap_windows binary_path, binary_args
|
262
|
+
raise ArgumentError.new("#{binary_path} doesn't exists") unless File.exists? binary_path
|
263
|
+
|
264
|
+
# service should be run with the same load path as a current application
|
265
|
+
load_path = get_load_path
|
266
|
+
# path that contains spaces must be escaped to be interpreted correctly
|
267
|
+
binary_path = %Q{"#{binary_path}"} if binary_path =~ / /
|
268
|
+
binary_args.insert(0, RUBY_INTERPRETER_PATH, load_path, binary_path.tr('/','\\'))
|
269
|
+
binary_path.replace(WRAPPER_SCRIPT)
|
270
|
+
end
|
271
|
+
|
272
|
+
# NOTE if this method will become public then may be needed to change appropriately wrapper script
|
273
|
+
def RunInBackground.stop name
|
274
|
+
if not exists? name
|
275
|
+
raise ArgumentError.new("Daemon #{name} doesn't exists")
|
276
|
+
elsif OS == :WINDOWS
|
277
|
+
Service.stop(name)
|
278
|
+
else # OS == :LINUX
|
279
|
+
opts = {:app_name => name,
|
280
|
+
:ARGV => ['stop'],
|
281
|
+
:dir_mode => :normal,
|
282
|
+
:dir => Params['pid_dir']
|
283
|
+
}
|
284
|
+
# Current process, that creates daemon, will transfer control to the Daemons library.
|
285
|
+
# So to continue working with current process, daemon creation initiated from separate process.
|
286
|
+
# It looks that it holds only for start command
|
287
|
+
#pid = fork do
|
288
|
+
Daemons.run "", opts
|
289
|
+
#end
|
290
|
+
#Process.waitpid pid
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Delete service/daemon.
|
295
|
+
# <br>If running then stop and delete.
|
296
|
+
def RunInBackground.delete name
|
297
|
+
if not exists? name
|
298
|
+
raise ArgumentError.new("Daemon #{name} doesn't exists")
|
299
|
+
elsif running? name
|
300
|
+
stop name
|
301
|
+
end
|
302
|
+
if OS == :WINDOWS
|
303
|
+
Service.delete name
|
304
|
+
else # OS == :LINUX
|
305
|
+
opts = {:app_name => name,
|
306
|
+
:ARGV => ['zap'],
|
307
|
+
:dir_mode => :normal,
|
308
|
+
:dir => Params['pid_dir']
|
309
|
+
}
|
310
|
+
# Current process, that creates daemon, will transfer control to the Daemons library.
|
311
|
+
# So to continue working with current process, daemon creation initiated from separate process.
|
312
|
+
# It looks that it holds only for start command
|
313
|
+
#pid = fork do
|
314
|
+
Daemons.run "", opts
|
315
|
+
#end
|
316
|
+
#Process.waitpid pid
|
317
|
+
end
|
318
|
+
0.upto(TIMEOUT) do
|
319
|
+
unless exists? name
|
320
|
+
puts "daemon/service #{name} deleted\n"
|
321
|
+
Log.debug1("daemon/service #{name} deleted")
|
322
|
+
return
|
323
|
+
end
|
324
|
+
sleep 1
|
325
|
+
end
|
326
|
+
# if got here then something gone wrong and daemon/service wasn't deleted in timely manner
|
327
|
+
Log.error("daemon/service #{name} wasn't deleted in timely manner")
|
328
|
+
Log.flush
|
329
|
+
raise "daemon/service #{name} wasn't deleted in timely manner"
|
330
|
+
end
|
331
|
+
|
332
|
+
def RunInBackground.exists? name
|
333
|
+
if name == nil
|
334
|
+
raise ArgumentError.new("service/daemon name argument must be defined")
|
335
|
+
elsif OS == :WINDOWS
|
336
|
+
Service.exists? name
|
337
|
+
else # OS == :LINUX
|
338
|
+
pid_files = Daemons::PidFile.find_files(Params['pid_dir'], name)
|
339
|
+
pid_files != nil && pid_files.size > 0
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def RunInBackground.running? name
|
344
|
+
if not exists? name
|
345
|
+
raise ArgumentError.new("Daemon #{name} doesn't exists")
|
346
|
+
elsif OS == :WINDOWS
|
347
|
+
Service.status(name).current_state == 'running'
|
348
|
+
else # OS == :LINUX
|
349
|
+
Daemons::Pid.running? name
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns absolute standard form of the path.
|
354
|
+
# It includes path separators accepted on this OS
|
355
|
+
def RunInBackground.get_abs_std_path path
|
356
|
+
path = File.expand_path path
|
357
|
+
path = path.tr('/','\\') if OS == :WINDOWS
|
358
|
+
path
|
359
|
+
end
|
360
|
+
|
361
|
+
# Returns load path as it provided in command line.
|
362
|
+
def RunInBackground.get_load_path
|
363
|
+
load_path = Array.new
|
364
|
+
$:.each do |location|
|
365
|
+
load_path << %Q{-I"#{get_abs_std_path(location)}"}
|
366
|
+
end
|
367
|
+
load_path.join ' '
|
368
|
+
end
|
369
|
+
|
370
|
+
# Prepare ARGV so it can be provided as a command line arguments.
|
371
|
+
# Remove bg_command from ARGV to prevent infinite recursion.
|
372
|
+
def RunInBackground.prepare_argv
|
373
|
+
new_argv = Array.new
|
374
|
+
ARGV.each do |arg|
|
375
|
+
# For each argument try splitting to 'name'='value'
|
376
|
+
arg_arr = arg.split '='
|
377
|
+
# If no '=' is argument, just copy paste.
|
378
|
+
if arg_arr.size == 1
|
379
|
+
arg = "\"#{arg}\"" if arg =~ / /
|
380
|
+
new_argv << arg
|
381
|
+
# If it is a 'name'='value' argument add "" so the value can be passed as argument again.
|
382
|
+
elsif arg_arr.size == 2
|
383
|
+
# Skip bg_command flag (remove infinite recursion)!
|
384
|
+
if arg_arr[0] !~ /bg_command/
|
385
|
+
arg_arr[1] = "\"#{arg_arr[1]}\"" if arg_arr[1] =~ / /
|
386
|
+
new_argv << arg_arr.join('=')
|
387
|
+
end
|
388
|
+
else
|
389
|
+
Log.warning("ARGV argument #{arg} wasn't processed")
|
390
|
+
new_argv << arg
|
391
|
+
end
|
392
|
+
end
|
393
|
+
ARGV.clear
|
394
|
+
ARGV.concat new_argv
|
395
|
+
end
|
396
|
+
|
397
|
+
def RunInBackground.run &b
|
398
|
+
case Params['bg_command']
|
399
|
+
when nil
|
400
|
+
yield b
|
401
|
+
when 'start'
|
402
|
+
# To prevent service enter loop cause of background parameter
|
403
|
+
# all options that points to run in background must be disabled
|
404
|
+
# (for more information see documentation for RunInBackground::start!)
|
405
|
+
Params['bg_command'] = nil
|
406
|
+
RunInBackground.prepare_argv
|
407
|
+
|
408
|
+
begin
|
409
|
+
RunInBackground.start! Params['service_name']
|
410
|
+
rescue Exception => e
|
411
|
+
Log.error("Start service command failed: #{e.message}")
|
412
|
+
raise
|
413
|
+
end
|
414
|
+
when 'delete'
|
415
|
+
if RunInBackground.exists? Params['service_name']
|
416
|
+
RunInBackground.delete Params['service_name']
|
417
|
+
else
|
418
|
+
msg = "Can't delete. Service #{Params['service_name']} already deleted"
|
419
|
+
puts msg
|
420
|
+
Log.warning(msg)
|
421
|
+
end
|
422
|
+
else
|
423
|
+
msg = "Unsupported command #{Params['bg_command']}. Supported commands are: start, delete"
|
424
|
+
puts msg
|
425
|
+
Log.error(msg)
|
426
|
+
end
|
427
|
+
nil
|
428
|
+
end
|
429
|
+
|
430
|
+
private_class_method :start_linux, :start_windows, :wrap_windows, :stop, :get_abs_std_path, \
|
431
|
+
:get_load_path
|
432
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'log4r'
|
2
|
+
require 'log'
|
3
|
+
require 'params'
|
4
|
+
require 'content_server'
|
5
|
+
require 'content_server/content_server' # specific content server impl
|
6
|
+
require 'content_server/backup_server' # specific backup server impl
|
7
|
+
require 'content_data'
|
8
|
+
require 'email'
|
9
|
+
require 'file_utils/file_generator/file_generator'
|
10
|
+
|
11
|
+
# Runs a memory test:
|
12
|
+
# 1. Run content server or backup server
|
13
|
+
# 2. Generate files.
|
14
|
+
# 3. Monitor files.
|
15
|
+
# 4. Index files.
|
16
|
+
# 5. Report memory of proces at different phases\times
|
17
|
+
# Examples:
|
18
|
+
# testing_server --conf_file=~/.bbfs/etc/backup_testing_memory.yml --server_to_test=backup
|
19
|
+
# testing_server --conf_file=~/.bbfs/etc/content_testing_memory.yml --server_to_test=content
|
20
|
+
|
21
|
+
module TestingMemory
|
22
|
+
|
23
|
+
Params.path('testing_log_path', nil, 'Testing server log path.')
|
24
|
+
Params.integer('memory_count_delay', 10, 'Memory report cycles in sec.')
|
25
|
+
Params.string('testing_title', 'Memory report', 'title to memory report')
|
26
|
+
Params.boolean('generate_files', true, 'if true, files will be generated.')
|
27
|
+
|
28
|
+
def init_log4r
|
29
|
+
#init log4r
|
30
|
+
log_path = Params['testing_log_path']
|
31
|
+
unless log_path
|
32
|
+
raise("pls specify testing log path through param:'testing_log_path'")
|
33
|
+
end
|
34
|
+
log_dir = File.dirname(log_path)
|
35
|
+
FileUtils.mkdir_p(log_dir) unless File.exists?(log_dir)
|
36
|
+
|
37
|
+
$testing_memory_log = Log4r::Logger.new 'BBFS testing server log'
|
38
|
+
$testing_memory_log.trace = true
|
39
|
+
formatter = Log4r::PatternFormatter.new(:pattern => "[%d] [%m]")
|
40
|
+
#file setup
|
41
|
+
file_config = {
|
42
|
+
"filename" => Params['testing_log_path'],
|
43
|
+
"trunc" => true
|
44
|
+
}
|
45
|
+
file_outputter = Log4r::FileOutputter.new("testing_log", file_config)
|
46
|
+
file_outputter.level = Log4r::INFO
|
47
|
+
file_outputter.formatter = formatter
|
48
|
+
$testing_memory_log.outputters << file_outputter
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_content_memory_server
|
52
|
+
$testing_memory_active = true # this activates debug messages to console
|
53
|
+
|
54
|
+
Log.info('Testing server started')
|
55
|
+
|
56
|
+
#Init log
|
57
|
+
init_log4r
|
58
|
+
$testing_memory_log.info('Testing server started')
|
59
|
+
|
60
|
+
#create files
|
61
|
+
if Params['generate_files']
|
62
|
+
total_files = Params['total_created_directories']*Params['total_files_in_dir']
|
63
|
+
$testing_memory_log.info("Creating #{total_files} files")
|
64
|
+
fg = FileGenerator::FileGenerator.new
|
65
|
+
fg.run
|
66
|
+
$testing_memory_log.info('Finished creating files')
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# run backup
|
71
|
+
Thread.new do
|
72
|
+
ContentServer.run_content_server
|
73
|
+
end
|
74
|
+
|
75
|
+
# run memory report cycles
|
76
|
+
check_memory_loop
|
77
|
+
|
78
|
+
raise("code should never reach here")
|
79
|
+
end
|
80
|
+
|
81
|
+
def run_backup_memory_server
|
82
|
+
$testing_memory_active = true # this activates debug messages to console
|
83
|
+
|
84
|
+
Log.info('Testing server started')
|
85
|
+
|
86
|
+
#Init log
|
87
|
+
init_log4r
|
88
|
+
$testing_memory_log.info('Testing server started')
|
89
|
+
|
90
|
+
#create files
|
91
|
+
if Params['generate_files']
|
92
|
+
total_files = Params['total_created_directories']*Params['total_files_in_dir']
|
93
|
+
$testing_memory_log.info("Creating #{total_files} files")
|
94
|
+
fg = FileGenerator::FileGenerator.new
|
95
|
+
fg.run
|
96
|
+
$testing_memory_log.info('Finished creating files')
|
97
|
+
end
|
98
|
+
|
99
|
+
# run backup
|
100
|
+
Thread.new do
|
101
|
+
ContentServer.run_backup_server
|
102
|
+
end
|
103
|
+
|
104
|
+
# run memory report cycles
|
105
|
+
check_memory_loop
|
106
|
+
|
107
|
+
raise("code should never reach here")
|
108
|
+
end
|
109
|
+
|
110
|
+
def check_memory_loop
|
111
|
+
start_time = Time.now
|
112
|
+
$testing_memory_log.info(Params['testing_title'])
|
113
|
+
total_files = Params['total_created_directories']*Params['total_files_in_dir']
|
114
|
+
$testing_memory_log.info("Start check all files:#{total_files} are indexed")
|
115
|
+
Params.get_init_info_messages.each { |msg|
|
116
|
+
$testing_memory_log.info(msg)
|
117
|
+
}
|
118
|
+
email_report = generate_mem_report
|
119
|
+
|
120
|
+
# memory loop
|
121
|
+
loop {
|
122
|
+
sleep(Params['memory_count_delay'])
|
123
|
+
email_report += generate_mem_report
|
124
|
+
email_report += "indexed files:#{$indexed_file_count}\n"
|
125
|
+
$testing_memory_log.info("indexed files:#{$indexed_file_count}")
|
126
|
+
puts "indexed files:#{$indexed_file_count}"
|
127
|
+
if total_files == $indexed_file_count
|
128
|
+
stop_time = Time.now
|
129
|
+
email_report += "\nAt this point all files are indexed. No mem changes should occur\n"
|
130
|
+
$testing_memory_log.info("Total indexing time = #{stop_time.to_i - start_time.to_i}[S]")
|
131
|
+
$testing_memory_log.info("\nAt this point all files are indexed. No mem changes should occur\n")
|
132
|
+
loop {
|
133
|
+
sleep(Params['memory_count_delay'])
|
134
|
+
email_report += generate_mem_report
|
135
|
+
}
|
136
|
+
#send_email("Final report:#{email_report}\nprocess memory:#{memory_of_process}\n")
|
137
|
+
end
|
138
|
+
}
|
139
|
+
end
|
140
|
+
|
141
|
+
def generate_mem_report
|
142
|
+
# Generate memory report
|
143
|
+
current_objects_counters = {}
|
144
|
+
|
145
|
+
count = ObjectSpace.each_object(String).count
|
146
|
+
current_objects_counters['String'] = count
|
147
|
+
count = ObjectSpace.each_object(ContentData::ContentData).count
|
148
|
+
current_objects_counters['ContentData'] = count
|
149
|
+
dir_count = ObjectSpace.each_object(FileMonitoring::DirStat).count
|
150
|
+
current_objects_counters['DirStat'] = dir_count
|
151
|
+
file_count = ObjectSpace.each_object(FileMonitoring::FileStat).count
|
152
|
+
current_objects_counters['FileStat'] = file_count-dir_count
|
153
|
+
|
154
|
+
# Generate report and update global counters
|
155
|
+
report = ""
|
156
|
+
current_objects_counters.each_key { |type|
|
157
|
+
report += "Type:#{type} count:#{current_objects_counters[type]} \n"
|
158
|
+
}
|
159
|
+
unless Gem::win_platform?
|
160
|
+
memory_of_process = `ps -o rss= -p #{Process.pid}`.to_i / 1000
|
161
|
+
else
|
162
|
+
memory_of_process = `tasklist /FI \"PID eq #{Process.pid}\" /NH /FO \"CSV\"`.split(',')[4]
|
163
|
+
end
|
164
|
+
final_report = "Time:#{Time.now}. Process memory:#{memory_of_process}[M]\nCount report:\n#{report}"
|
165
|
+
puts "Process memory:#{memory_of_process}[M]"
|
166
|
+
$testing_memory_log.info(final_report)
|
167
|
+
final_report
|
168
|
+
end
|
169
|
+
|
170
|
+
def send_email(report)
|
171
|
+
|
172
|
+
msg =<<EOF
|
173
|
+
#{report}
|
174
|
+
EOF
|
175
|
+
Email.send_email(Params['from_email'],
|
176
|
+
Params['from_email_password'],
|
177
|
+
Params['to_email'],
|
178
|
+
'Memory server update',
|
179
|
+
msg)
|
180
|
+
end
|
181
|
+
|
182
|
+
module_function :run_content_memory_server, :run_backup_memory_server, :init_log4r, :send_email
|
183
|
+
module_function :check_memory_loop, :generate_mem_report
|
184
|
+
|
185
|
+
end # module TestingServer
|
186
|
+
|
187
|
+
|