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.
- 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
|
+
|