content_server 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/backup_server +8 -20
- data/bin/content_server +8 -20
- data/bin/testing_memory +60 -0
- data/bin/testing_server +57 -0
- data/ext/run_in_background/mkrf_conf.rb +34 -0
- data/lib/content_data/content_data.rb +613 -0
- data/lib/content_data/version.rb +3 -0
- data/lib/content_data.rb +6 -0
- data/lib/content_server/backup_server.rb +65 -86
- data/lib/content_server/content_server.rb +47 -77
- data/lib/content_server/file_streamer.rb +27 -33
- data/lib/content_server/queue_copy.rb +154 -49
- data/lib/content_server/queue_indexer.rb +19 -11
- data/lib/content_server/remote_content.rb +41 -23
- data/lib/content_server/server.rb +91 -0
- data/lib/content_server/version.rb +1 -1
- data/lib/content_server.rb +0 -15
- data/lib/email/email.rb +87 -0
- data/lib/email/version.rb +3 -0
- data/lib/email.rb +4 -0
- data/lib/file_copy/copy.rb +68 -0
- data/lib/file_copy/version.rb +4 -0
- data/lib/file_copy.rb +4 -0
- data/lib/file_indexing/index_agent.rb +170 -0
- data/lib/file_indexing/indexer_patterns.rb +72 -0
- data/lib/file_indexing/version.rb +3 -0
- data/lib/file_indexing.rb +9 -0
- data/lib/file_monitoring/file_monitoring.rb +105 -0
- data/lib/file_monitoring/monitor_path.rb +304 -0
- data/lib/file_monitoring/version.rb +3 -0
- data/lib/file_monitoring.rb +29 -0
- data/lib/file_utils/file_generator/README +97 -0
- data/lib/file_utils/file_generator/file_generator.rb +156 -0
- data/lib/file_utils/file_utils.rb +260 -0
- data/lib/file_utils/version.rb +3 -0
- data/lib/file_utils.rb +4 -0
- data/lib/log/version.rb +3 -0
- data/lib/log.rb +188 -0
- data/lib/networking/tcp.rb +213 -0
- data/lib/networking/version.rb +3 -0
- data/lib/networking.rb +4 -0
- data/lib/params/version.rb +3 -0
- data/lib/params.rb +419 -0
- data/lib/process_monitoring/monitoring.rb +85 -0
- data/lib/process_monitoring/monitoring_info.rb +79 -0
- data/lib/process_monitoring/send_email.rb +40 -0
- data/lib/process_monitoring/thread_safe_hash.rb +77 -0
- data/lib/process_monitoring/version.rb +3 -0
- data/lib/process_monitoring.rb +6 -0
- data/lib/run_in_background/version.rb +3 -0
- data/lib/run_in_background.rb +432 -0
- data/lib/testing_memory/testing_memory.rb +187 -0
- data/lib/testing_server/testing_server.rb +236 -0
- data/lib/testing_server/version.rb +3 -0
- data/lib/testing_server.rb +12 -0
- data/lib/validations/index_validations.rb +106 -0
- data/lib/validations/version.rb +3 -0
- data/lib/validations.rb +4 -0
- data/spec/content_data/validations_spec.rb +113 -0
- data/spec/file_copy/copy_spec.rb +54 -0
- data/spec/file_indexing/index_agent_spec.rb +53 -0
- data/spec/networking/tcp_spec.rb +95 -0
- data/spec/validations/index_validations_spec.rb +77 -0
- data/test/content_data/content_data_test.rb +290 -0
- data/test/file_generator/file_generator_spec.rb +84 -0
- data/test/file_indexing/index_agent_test/New.txt +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libexslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/libxslt.dll +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/bin/xsltproc.exe +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exslt.h +102 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltconfig.h +73 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/exsltexports.h +140 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libexslt/libexslt.h +29 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/attributes.h +38 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/documents.h +93 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extensions.h +262 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/extra.h +80 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/functions.h +78 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/imports.h +75 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/keys.h +53 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/libxslt.h +30 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/namespaces.h +68 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/numbersInternals.h +69 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/pattern.h +81 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/preproc.h +43 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/security.h +104 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/templates.h +77 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/transform.h +207 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/trio.h +216 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/triodef.h +220 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/variables.h +91 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/win32config.h +101 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xslt.h +103 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltInternals.h +1967 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltconfig.h +172 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltexports.h +142 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltlocale.h +57 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltutils.h +309 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/include/libxslt/xsltwin32config.h +105 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libexslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/lib/libxslt_a.lib +0 -0
- data/test/file_indexing/index_agent_test/libxslt-1.1.26.win32/readme.txt +22 -0
- data/test/file_indexing/index_agent_test/patterns.input +3 -0
- data/test/file_indexing/index_agent_test.rb +51 -0
- data/test/file_monitoring/file_monitoring_test/conf.yml +4 -0
- data/test/file_monitoring/file_monitoring_test/conf_win32.yml +5 -0
- data/test/file_monitoring/file_monitoring_test/log +56 -0
- data/test/file_monitoring/file_monitoring_test.rb +0 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.0 +1500 -0
- data/test/file_monitoring/monitor_path_test/dir1500/test_file.1500.1 +1500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.0 +500 -0
- data/test/file_monitoring/monitor_path_test/test_file.500.1 +500 -0
- data/test/file_monitoring/monitor_path_test.rb +153 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.0 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/dir1500/test_file.1500.1 +1500 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.0 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/dir1000/test_file.1000.1 +1000 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.0 +500 -0
- data/test/file_utils/fileutil_mksymlink_test/test_file.500.1 +500 -0
- data/test/file_utils/fileutil_mksymlink_test.rb +125 -0
- data/test/file_utils/time_modification_test.rb +132 -0
- data/test/params/params_spec.rb +280 -0
- data/test/params/params_test.rb +43 -0
- data/test/run_in_background/run_in_background_test.rb +122 -0
- data/test/run_in_background/test_app +57 -0
- metadata +272 -132
- data/lib/content_server/globals.rb +0 -10
data/lib/email/email.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
module Email
|
4
|
+
|
5
|
+
def Email.send_raw_email(from, password, to, mail_text)
|
6
|
+
smtp = Net::SMTP.new('smtp.gmail.com', 587)
|
7
|
+
smtp.enable_starttls
|
8
|
+
smtp.start(from.split('@')[-1], from, password, :login) do
|
9
|
+
smtp.send_message(mail_text, from, to)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def Email.send_email(from, password, to, subject, body)
|
14
|
+
marker = (0...50).map{ ('a'..'z').to_a[rand(26)] }.join
|
15
|
+
parts = []
|
16
|
+
parts << <<EOF
|
17
|
+
From: #{from}
|
18
|
+
To: #{to}
|
19
|
+
Subject: #{subject}
|
20
|
+
MIME-Version: 1.0
|
21
|
+
Content-Type: multipart/mixed; boundary=#{marker}
|
22
|
+
--#{marker}
|
23
|
+
EOF
|
24
|
+
|
25
|
+
# Define the message action
|
26
|
+
parts << <<EOF
|
27
|
+
Content-Type: text/plain
|
28
|
+
Content-Transfer-Encoding:8bit
|
29
|
+
|
30
|
+
#{body}
|
31
|
+
--#{marker}
|
32
|
+
EOF
|
33
|
+
|
34
|
+
mailtext = parts.join('')
|
35
|
+
send_raw_email(from, password, to, mailtext)
|
36
|
+
end
|
37
|
+
|
38
|
+
def Email.send_attachments_email(from, password, to, subject, body, attachments)
|
39
|
+
# Read a file and encode it into base64 format
|
40
|
+
begin
|
41
|
+
encoded_attachments = []
|
42
|
+
attachments.each do |attachment|
|
43
|
+
file_content = File.read(attachment)
|
44
|
+
encoded_content = [file_content].pack("m") # base64
|
45
|
+
encoded_attachments << [attachment, encoded_content]
|
46
|
+
end
|
47
|
+
rescue
|
48
|
+
raise "Could not read file #{attachment}"
|
49
|
+
end
|
50
|
+
|
51
|
+
marker = (0...50).map{ ('a'..'z').to_a[rand(26)] }.join
|
52
|
+
parts = []
|
53
|
+
parts << <<EOF
|
54
|
+
From: #{from}
|
55
|
+
To: #{to}
|
56
|
+
Subject: #{subject}
|
57
|
+
MIME-Version: 1.0
|
58
|
+
Content-Type: multipart/mixed; boundary=#{marker}
|
59
|
+
--#{marker}
|
60
|
+
EOF
|
61
|
+
|
62
|
+
# Define the message action
|
63
|
+
parts << <<EOF
|
64
|
+
Content-Type: text/plain
|
65
|
+
Content-Transfer-Encoding:8bit
|
66
|
+
|
67
|
+
#{body}
|
68
|
+
--#{marker}
|
69
|
+
EOF
|
70
|
+
|
71
|
+
encoded_attachments.each do |attachment, encoded_content|
|
72
|
+
# Define the attachment section
|
73
|
+
parts << <<EOF
|
74
|
+
Content-Type: multipart/mixed; name=\"#{File.basename(attachment)}\"
|
75
|
+
Content-Transfer-Encoding:base64
|
76
|
+
Content-Disposition: attachment; filename="#{File.basename(attachment)}"
|
77
|
+
|
78
|
+
#{encoded_content}
|
79
|
+
--#{marker}--
|
80
|
+
EOF
|
81
|
+
end
|
82
|
+
|
83
|
+
mailtext = parts.join('')
|
84
|
+
send_raw_email(from, password, to, mailtext)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
data/lib/email.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'net/ssh'
|
2
|
+
require 'net/sftp'
|
3
|
+
|
4
|
+
require 'log'
|
5
|
+
require 'params'
|
6
|
+
|
7
|
+
module FileCopy
|
8
|
+
|
9
|
+
# Creates ssh connection, assumes username and password
|
10
|
+
# or without password but with ssh keys.
|
11
|
+
def ssh_connect(username, password, server)
|
12
|
+
username = (username and username.length > 0) ? username : ENV['USER']
|
13
|
+
password = (password and password.length > 0) ? password : nil
|
14
|
+
port = 22 # 22 is a standart SSH port
|
15
|
+
raise "Undefined server" unless server
|
16
|
+
Log.debug1 "Trying to connect(ssh): #{username}, #{password}, #{server}, #{port}."
|
17
|
+
if (username and password)
|
18
|
+
Net::SSH.start(server, username,
|
19
|
+
:password => password,
|
20
|
+
:port => port)
|
21
|
+
elsif (username)
|
22
|
+
Net::SSH.start(server, username,
|
23
|
+
:port => port)
|
24
|
+
else
|
25
|
+
raise "Undefined username"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
module_function :ssh_connect
|
29
|
+
|
30
|
+
# Simply copy map files using sftp server on dest_server.
|
31
|
+
# Note: stfp.upload support parallel uploads - default is 2.
|
32
|
+
# TODO(kolman): packing files, all, not all, determine by part of file.
|
33
|
+
def sftp_copy(username, password, server, files_map)
|
34
|
+
ssh = FileCopy.ssh_connect(username, password, server)
|
35
|
+
ssh.sftp.connect do |sftp|
|
36
|
+
uploads = files_map.map { |from,to|
|
37
|
+
remote_dir = File.dirname(to)
|
38
|
+
sftp_mkdir_recursive(sftp, File.dirname(to))
|
39
|
+
Log.debug1 "Copying #{from} to #{to}"
|
40
|
+
sftp.upload(from, to)
|
41
|
+
}
|
42
|
+
uploads.each { |u| u.wait }
|
43
|
+
Log.debug1 "Done."
|
44
|
+
end # ssh.sftp.connect
|
45
|
+
end # def initialize
|
46
|
+
module_function :sftp_copy
|
47
|
+
|
48
|
+
def sftp_mkdir_recursive(sftp, path)
|
49
|
+
dir_stat = nil
|
50
|
+
begin
|
51
|
+
Log.debug1 "Stat remote dir: #{path}."
|
52
|
+
dir_stat = sftp.stat!(path).directory?
|
53
|
+
Log.debug1 "Stat result #{dir_stat}."
|
54
|
+
rescue Net::SFTP::StatusException
|
55
|
+
end
|
56
|
+
if !dir_stat
|
57
|
+
Log.debug1 "Directory does not exists: #{path}."
|
58
|
+
sftp_mkdir_recursive sftp, File.dirname(path)
|
59
|
+
Log.debug1 "Making dir #{path}."
|
60
|
+
response = sftp.mkdir!(path)
|
61
|
+
Log.debug1 "Making dir ok:#{response.ok?}."
|
62
|
+
end
|
63
|
+
end
|
64
|
+
module_function :sftp_mkdir_recursive
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
|
data/lib/file_copy.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'pp'
|
3
|
+
require 'set'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
require 'content_data'
|
7
|
+
require 'file_indexing/indexer_patterns'
|
8
|
+
require 'log'
|
9
|
+
|
10
|
+
|
11
|
+
module FileIndexing
|
12
|
+
####################
|
13
|
+
# Index Agent
|
14
|
+
####################
|
15
|
+
|
16
|
+
class IndexAgent
|
17
|
+
attr_reader :indexed_content, :failed_files
|
18
|
+
|
19
|
+
# Why are those lines needed?
|
20
|
+
LOCALTZ = Time.now.zone
|
21
|
+
ENV['TZ'] = 'UTC'
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@indexed_content = ContentData::ContentData.new
|
25
|
+
@failed_files = Set.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# Calculate file checksum (SHA1)
|
29
|
+
def self.get_checksum(filename)
|
30
|
+
digest = Digest::SHA1.new
|
31
|
+
begin
|
32
|
+
File.open(filename, 'rb') { |f|
|
33
|
+
while buffer = f.read(65536) do
|
34
|
+
digest << buffer
|
35
|
+
end
|
36
|
+
}
|
37
|
+
Log.debug1("#{filename} sha1 #{digest.hexdigest.downcase}")
|
38
|
+
digest.hexdigest.downcase
|
39
|
+
rescue Errno::EACCES, Errno::ETXTBSY => exp
|
40
|
+
Log.warning("#{exp.message}")
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def IndexAgent.get_content_checksum(content)
|
46
|
+
# Calculate checksum.
|
47
|
+
digest = Digest::SHA1.new
|
48
|
+
digest << content
|
49
|
+
digest.hexdigest.downcase
|
50
|
+
end
|
51
|
+
|
52
|
+
# get all files
|
53
|
+
# satisfying the pattern
|
54
|
+
def collect(pattern)
|
55
|
+
Dir.glob(pattern.to_s)
|
56
|
+
end
|
57
|
+
|
58
|
+
# TODO(kolman): Replace this with File.lstat(file).mtime when new version of Ruby comes out.
|
59
|
+
# http://bugs.ruby-lang.org/issues/6385
|
60
|
+
def IndexAgent.get_correct_mtime(file)
|
61
|
+
begin
|
62
|
+
File.open(file, 'r') { |f| f.mtime }
|
63
|
+
rescue Errno::EACCES => e
|
64
|
+
Log.warning("Could not open file #{file} to get mtime. #{e}")
|
65
|
+
return 0
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# index device according to the pattern
|
70
|
+
# store the result
|
71
|
+
# does not adds automatically otherDB to stored result
|
72
|
+
# TODO device support
|
73
|
+
def index(patterns, otherDB = nil)
|
74
|
+
abort "#{self.class}: DB not empty. Current implementation permits only one running of index" \
|
75
|
+
unless @indexed_content.empty?
|
76
|
+
local_server_name = `hostname`.strip
|
77
|
+
permit_patterns = []
|
78
|
+
forbid_patterns = []
|
79
|
+
otherDB_updated = ContentData::ContentData.new
|
80
|
+
#otherDB_table = Hash.new # contains instances from given DB while full path name is a key and instance is a value
|
81
|
+
#otherDB_contents = Hash.new # given DB contents
|
82
|
+
|
83
|
+
# if there is a given DB then populate table with files
|
84
|
+
# that was already indexed on this server/device
|
85
|
+
if !otherDB.nil?
|
86
|
+
otherDB.each_instance { |checksum, size, content_mod_time, instance_mod_time, server, path|
|
87
|
+
if (server == local_server_name)
|
88
|
+
# add instance
|
89
|
+
otherDB_updated.add_instance(checksum, size, server, path, instance_mod_time)
|
90
|
+
end
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
permit_patterns = patterns.positive_patterns
|
95
|
+
forbid_patterns = patterns.negative_patterns
|
96
|
+
|
97
|
+
# add files found by positive patterns
|
98
|
+
files = Array.new
|
99
|
+
permit_patterns.each_index do |i|
|
100
|
+
files = files | (collect(permit_patterns[i]));
|
101
|
+
end
|
102
|
+
|
103
|
+
Log.debug1 "Files: #{files}."
|
104
|
+
|
105
|
+
# expand to absolute pathes
|
106
|
+
files.map! {|f| File.expand_path(f)}
|
107
|
+
|
108
|
+
# remove files found by negative patterns
|
109
|
+
forbid_patterns.each_index do |i|
|
110
|
+
forbid_files = Array.new(collect(forbid_patterns[i]));
|
111
|
+
forbid_files.each do |f|
|
112
|
+
files.delete(File.expand_path(f))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# create and add contents and instances
|
117
|
+
files.each do |file|
|
118
|
+
file_stats = File.lstat(file)
|
119
|
+
file_mtime = IndexAgent.get_correct_mtime(file)
|
120
|
+
device = file_stats.dev.to_s
|
121
|
+
|
122
|
+
# index only files
|
123
|
+
next if file_stats.directory?
|
124
|
+
|
125
|
+
# add files present in the given DB to the DB and remove these files
|
126
|
+
# from further processing (save checksum calculation)
|
127
|
+
file_match = false
|
128
|
+
otherDB_updated.each_instance { |checksum, size, content_mod_time, instance_mod_time, server, path|
|
129
|
+
if otherDB_updated.instance_exists(file, local_server_name, checksum)
|
130
|
+
if size == file_stats.size and instance_mod_time == file_mtime.to_i
|
131
|
+
@indexed_content.add_instance(checksum, size, server, file, instance_mod_time)
|
132
|
+
file_match = true
|
133
|
+
break
|
134
|
+
else
|
135
|
+
Log.warning("File (#{file}) size or modification file is different. size=#{size} actual size=#{file_stats.size}" + \
|
136
|
+
" instance_mod_time=#{Time.at(instance_mod_time)} actual=#{file_mtime}")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
}
|
140
|
+
next if file_match
|
141
|
+
# calculate a checksum
|
142
|
+
unless (checksum = self.class.get_checksum(file))
|
143
|
+
Log.warning("Cheksum failure: " + file)
|
144
|
+
@failed_files.add(file)
|
145
|
+
next
|
146
|
+
end
|
147
|
+
|
148
|
+
@indexed_content.add_instance(checksum, file_stats.size, local_server_name,
|
149
|
+
File.expand_path(file), file_mtime.to_i)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def IndexAgent.create_shallow_instance(filename)
|
154
|
+
return nil unless File.exists?(filename)
|
155
|
+
file_stats = File.lstat(filename)
|
156
|
+
file_mtime = IndexAgent.get_correct_mtime(filename)
|
157
|
+
# return instance shallow representation (no server)
|
158
|
+
[file_stats.size,
|
159
|
+
"%s,%s,%s" % [`hostname`.strip , file_stats.dev.to_s , File.expand_path(filename)],
|
160
|
+
file_mtime.to_i]
|
161
|
+
end
|
162
|
+
|
163
|
+
def IndexAgent.global_path(filename)
|
164
|
+
server_name = `hostname`.strip
|
165
|
+
file_stats = File.lstat(filename)
|
166
|
+
return "%s,%s,%s" % [server_name, file_stats.dev.to_s,filename]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'log'
|
2
|
+
require 'params'
|
3
|
+
|
4
|
+
module FileIndexing
|
5
|
+
|
6
|
+
class IndexerPatterns
|
7
|
+
attr_reader :positive_patterns, :negative_patterns
|
8
|
+
|
9
|
+
# @param indexer_patterns_str [String]
|
10
|
+
def initialize (indexer_patterns = nil)
|
11
|
+
Log.debug1 "Initialize index patterns #{indexer_patterns}."
|
12
|
+
@positive_patterns = Array.new
|
13
|
+
@negative_patterns = Array.new
|
14
|
+
# TODO add a test (including empty collections)
|
15
|
+
if indexer_patterns
|
16
|
+
indexer_patterns.positive_patterns.each do |pattern|
|
17
|
+
add_pattern(pattern)
|
18
|
+
end
|
19
|
+
indexer_patterns.negative_patterns.each do |pattern|
|
20
|
+
add_pattern(pattern, false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def serialize
|
26
|
+
# TODO add a test (including empty collections)
|
27
|
+
indexer_patterns = IndexerPatternsMessage.new
|
28
|
+
positive_patterns.each do |pattern|
|
29
|
+
indexer_patterns.positive_patterns << pattern
|
30
|
+
end
|
31
|
+
negative_patterns.each do |pattern|
|
32
|
+
indexer_patterns.negative_patterns << pattern
|
33
|
+
end
|
34
|
+
indexer_patterns
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param pattern [String]
|
38
|
+
# @param is_positive [true]
|
39
|
+
# @param is_positive [false]
|
40
|
+
def add_pattern(pattern, is_positive = true)
|
41
|
+
pattern.gsub!(/\\/,'/')
|
42
|
+
if (is_positive)
|
43
|
+
@positive_patterns << pattern
|
44
|
+
else
|
45
|
+
@negative_patterns << pattern
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_from_file(file)
|
50
|
+
input_patterns = IO.readlines(file)
|
51
|
+
begin
|
52
|
+
Log.debug1 "Error loading patterns=%s" % file
|
53
|
+
raise IOError("Error loading patterns=%s" % file)
|
54
|
+
end unless not input_patterns.nil?
|
55
|
+
|
56
|
+
input_patterns.each do |pattern|
|
57
|
+
if (m = /^\s*([+-]):(.*)/.match(pattern))
|
58
|
+
add_pattern(m[2], m[1].eql?('+') ? true : false)
|
59
|
+
elsif (not /^\s*[\/\/|#]/.match(pattern)) # not a comment
|
60
|
+
Log.debug1 "pattern in incorrect format: #{pattern}"
|
61
|
+
raise RuntimeError("pattern in incorrect format: #{pattern}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def size
|
67
|
+
return @positive_patterns.size
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'algorithms'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'log4r'
|
4
|
+
require 'params'
|
5
|
+
require 'content_server/server'
|
6
|
+
require 'file_monitoring/monitor_path'
|
7
|
+
|
8
|
+
module FileMonitoring
|
9
|
+
# Manages file monitoring of number of file system locations
|
10
|
+
class FileMonitoring
|
11
|
+
|
12
|
+
def initialize ()
|
13
|
+
@content_data_cache = Set.new
|
14
|
+
$local_content_data_lock.synchronize {
|
15
|
+
$local_content_data.each_instance(){
|
16
|
+
|_, _, _, _, _, file_path|
|
17
|
+
# save files to cache
|
18
|
+
Log.info("File in cache: #{file_path.clone}")
|
19
|
+
@content_data_cache.add(file_path.clone)
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Set event queue used for communication between different proceses.
|
26
|
+
# @param queue [Queue]
|
27
|
+
def set_event_queue(queue)
|
28
|
+
@event_queue = queue
|
29
|
+
end
|
30
|
+
|
31
|
+
# The main method. Loops on all paths, each time span and monitors them.
|
32
|
+
#
|
33
|
+
# =Algorithm:
|
34
|
+
# There is a loop that performs at every iteration:
|
35
|
+
# 1.Pull entry with a minimal time of check from queue
|
36
|
+
# 2.Recursively check path taken from entry for changes
|
37
|
+
# a.Notify subscribed processes on changes
|
38
|
+
# 3.Push entry to the queue with new time of next check
|
39
|
+
#
|
40
|
+
# This methods controlled by <tt>monitoring_paths</tt> configuration parameter,
|
41
|
+
# that provides path and file monitoring configuration data
|
42
|
+
def monitor_files
|
43
|
+
conf_array = Params['monitoring_paths']
|
44
|
+
# Directories states stored in the priority queue,
|
45
|
+
# where the key (priority) is a time when it should be checked next time.
|
46
|
+
# Priority queue means that all entries arranged by key (time to check) in increasing order.
|
47
|
+
pq = Containers::PriorityQueue.new
|
48
|
+
conf_array.each { |elem|
|
49
|
+
priority = (Time.now + elem['scan_period']).to_i
|
50
|
+
dir_stat = DirStat.new(File.expand_path(elem['path']), elem['stable_state'], @content_data_cache, FileStatEnum::NON_EXISTING)
|
51
|
+
dir_stat.set_event_queue(@event_queue) if @event_queue
|
52
|
+
Log.debug1("File monitoring started for: #{elem}")
|
53
|
+
pq.push([priority, elem, dir_stat], -priority)
|
54
|
+
}
|
55
|
+
|
56
|
+
#init log4r
|
57
|
+
monitoring_log_path = Params['default_monitoring_log_path']
|
58
|
+
Log.debug1 'File monitoring log: ' + Params['default_monitoring_log_path']
|
59
|
+
monitoring_log_dir = File.dirname(monitoring_log_path)
|
60
|
+
FileUtils.mkdir_p(monitoring_log_dir) unless File.exists?(monitoring_log_dir)
|
61
|
+
|
62
|
+
@log4r = Log4r::Logger.new 'BBFS monitoring log'
|
63
|
+
@log4r.trace = true
|
64
|
+
formatter = Log4r::PatternFormatter.new(:pattern => "[%d] [%m]")
|
65
|
+
#file setup
|
66
|
+
file_config = {
|
67
|
+
"filename" => Params['default_monitoring_log_path'],
|
68
|
+
"maxsize" => Params['log_rotation_size'],
|
69
|
+
"trunc" => true
|
70
|
+
}
|
71
|
+
file_outputter = Log4r::RollingFileOutputter.new("monitor_log", file_config)
|
72
|
+
file_outputter.level = Log4r::INFO
|
73
|
+
file_outputter.formatter = formatter
|
74
|
+
@log4r.outputters << file_outputter
|
75
|
+
FileStat.set_log(@log4r)
|
76
|
+
|
77
|
+
while true do
|
78
|
+
# pull entry that should be checked next,
|
79
|
+
# according to it's scan_period
|
80
|
+
time, conf, dir_stat = pq.pop
|
81
|
+
# time remains to wait before directory should be checked
|
82
|
+
time_span = time - Time.now.to_i
|
83
|
+
if (time_span > 0)
|
84
|
+
sleep(time_span)
|
85
|
+
end
|
86
|
+
|
87
|
+
unless $testing_memory_active
|
88
|
+
dir_stat.monitor
|
89
|
+
else
|
90
|
+
$testing_memory_log.info("Start monitor at :#{Time.now}")
|
91
|
+
puts "Start monitor at :#{Time.now}"
|
92
|
+
dir_stat.monitor
|
93
|
+
$testing_memory_log.info("End monitor at :#{Time.now}")
|
94
|
+
puts "End monitor at :#{Time.now}"
|
95
|
+
end
|
96
|
+
|
97
|
+
# push entry with new a next time it should be checked as a priority key
|
98
|
+
priority = (Time.now + conf['scan_period']).to_i
|
99
|
+
pq.push([priority, conf, dir_stat], -priority)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|