evesync 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +25 -0
  3. data/Rakefile +83 -0
  4. data/bin/evedatad +34 -0
  5. data/bin/evehand +36 -0
  6. data/bin/evemond +42 -0
  7. data/bin/evesync +164 -0
  8. data/bin/evesyncd +44 -0
  9. data/bin/start +16 -0
  10. data/config/example.conf +58 -0
  11. data/lib/evesync/config.rb +63 -0
  12. data/lib/evesync/constants.rb +17 -0
  13. data/lib/evesync/database.rb +107 -0
  14. data/lib/evesync/discover.rb +77 -0
  15. data/lib/evesync/err.rb +25 -0
  16. data/lib/evesync/handler/file.rb +28 -0
  17. data/lib/evesync/handler/package.rb +30 -0
  18. data/lib/evesync/handler.rb +89 -0
  19. data/lib/evesync/ipc/client.rb +37 -0
  20. data/lib/evesync/ipc/data/file.rb +64 -0
  21. data/lib/evesync/ipc/data/hashable.rb +74 -0
  22. data/lib/evesync/ipc/data/ignore.rb +22 -0
  23. data/lib/evesync/ipc/data/package.rb +58 -0
  24. data/lib/evesync/ipc/data/utils.rb +14 -0
  25. data/lib/evesync/ipc/data.rb +50 -0
  26. data/lib/evesync/ipc/ipc.rb +42 -0
  27. data/lib/evesync/ipc/server.rb +56 -0
  28. data/lib/evesync/log.rb +66 -0
  29. data/lib/evesync/ntp.rb +16 -0
  30. data/lib/evesync/os/linux/arch/package_manager.rb +29 -0
  31. data/lib/evesync/os/linux/arch/package_watcher.rb +59 -0
  32. data/lib/evesync/os/linux/arch.rb +2 -0
  33. data/lib/evesync/os/linux/base_package_manager.rb +80 -0
  34. data/lib/evesync/os/linux/deb/dpkg.rb +30 -0
  35. data/lib/evesync/os/linux/deb/package_manager.rb +38 -0
  36. data/lib/evesync/os/linux/deb/package_watcher.rb +32 -0
  37. data/lib/evesync/os/linux/deb.rb +2 -0
  38. data/lib/evesync/os/linux/rhel/package_manager.rb +42 -0
  39. data/lib/evesync/os/linux/rhel/package_watcher.rb +32 -0
  40. data/lib/evesync/os/linux/rhel/rpm.rb +41 -0
  41. data/lib/evesync/os/linux/rhel.rb +3 -0
  42. data/lib/evesync/os/linux.rb +9 -0
  43. data/lib/evesync/os.rb +2 -0
  44. data/lib/evesync/sync.rb +209 -0
  45. data/lib/evesync/trigger/base.rb +56 -0
  46. data/lib/evesync/trigger/file.rb +20 -0
  47. data/lib/evesync/trigger/package.rb +20 -0
  48. data/lib/evesync/trigger.rb +106 -0
  49. data/lib/evesync/utils.rb +51 -0
  50. data/lib/evesync/watcher/file.rb +156 -0
  51. data/lib/evesync/watcher/interface.rb +21 -0
  52. data/lib/evesync/watcher/package.rb +8 -0
  53. data/lib/evesync/watcher.rb +68 -0
  54. data/lib/evesync.rb +3 -0
  55. metadata +198 -0
@@ -0,0 +1,66 @@
1
+ require 'logger'
2
+ require 'evesync/config'
3
+ require 'evesync/constants'
4
+
5
+ # This module is responsible for logging
6
+ module Evesync
7
+ module Log
8
+ # Supported levels for logging
9
+ LEVELS = %i[debug info warn error fatal].freeze
10
+
11
+ class << self
12
+ def method_missing(m, *args)
13
+ # Unlisted methods are not allowed
14
+ raise NoMethodError unless LEVELS.include?(m)
15
+
16
+ check_logger
17
+ @logger.send(m, to_string(*args))
18
+ nil
19
+ end
20
+
21
+ def check_logger
22
+ init_logger unless @logger
23
+ end
24
+
25
+ def level=(lvl)
26
+ check_logger
27
+ if lvl.is_a?(Symbol) or lvl.is_a?(String)
28
+ @logger.level =
29
+ begin
30
+ Logger.const_get(lvl.to_s.upcase)
31
+ rescue NameError
32
+ Logger::DEBUG
33
+ end
34
+ end
35
+ end
36
+
37
+ def level
38
+ check_logger
39
+ @logger.level
40
+ end
41
+
42
+ def simple=(bool)
43
+ init_logger unless @logger
44
+ if bool
45
+ @logger.formatter = proc do |_sev, _dt, _prog, msg|
46
+ "#{msg}\n"
47
+ end
48
+ end
49
+ end
50
+
51
+ def init_logger
52
+ @logger = Logger.new(STDERR)
53
+ @logger.formatter = proc do |sev, dtime, _prog, msg|
54
+ time = dtime.strftime('%Y-%m-%d %H:%M:%S')
55
+ prog = File.basename($PROGRAM_NAME)
56
+ "[#{time}] #{prog.ljust(8)} #{sev.ljust(5)}: #{msg}\n"
57
+ end
58
+ end
59
+
60
+ def to_string(*args)
61
+ to_s_with_space = ->(s) { "#{s} " }
62
+ args.map(&to_s_with_space).reduce(&:+).strip
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,16 @@
1
+ require 'net/ntp'
2
+ require 'evesync/config'
3
+
4
+ module Evesync
5
+ module NTP
6
+
7
+ def self.time
8
+ Net::NTP.get(Config['ntp']).time
9
+ end
10
+
11
+ def self.timestamp
12
+ time.to_f.to_s
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module Evesync
2
+ module OS
3
+ # FIXME: pacman downgrading requires full url path
4
+ module PackageManager
5
+ class << self
6
+ def install(*args)
7
+ pacman('-Sy', *args)
8
+ end
9
+
10
+ def remove(*args)
11
+ pacman('-R', *args)
12
+ end
13
+
14
+ # FIXME: update and downgrade specific version is not fine
15
+ def update(*args)
16
+ pacman('-U', *args)
17
+ end
18
+
19
+ def downgrade(*args)
20
+ pacman('-U', *args)
21
+ end
22
+
23
+ def pacman(cmd, name, _version)
24
+ `pacman #{cmd} #{name}` # FIXME: do smth with version
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,59 @@
1
+ require 'file-tail'
2
+ require 'evesync/log'
3
+ require 'evesync/config'
4
+ require 'evesync/ipc/data/package'
5
+ require 'evesync/watcher/interface'
6
+
7
+ module Evesync
8
+ module OS
9
+
10
+ # Watcher for package changes for Arch Linux
11
+ #
12
+ # = Example
13
+ # Thread.new { IPC::Data::PackageWatcher.new(queue).run }
14
+ class PackageWatcher < Watcher::Interface
15
+ ARCH_LOG_FILE = '/var/log/pacman.log'.freeze
16
+ PKG_REGEXP =
17
+ /(?<command>reinstalled|installed|removed)
18
+ \s*
19
+ (?<package>\w+)
20
+ \s*
21
+ \( (?<version>[\w\d.-]+) \)
22
+ /x.freeze
23
+
24
+ private_constant :ARCH_LOG_FILE, :PKG_REGEXP
25
+
26
+ def initialize(queue)
27
+ @queue = queue
28
+ Log.debug('Arch Package watcher initialized')
29
+ end
30
+
31
+ def start
32
+ Log.debug('Arch Package watcher started')
33
+ @thr = Thread.new do
34
+ File.open(ARCH_LOG_FILE) do |log|
35
+ log.extend(File::Tail)
36
+ log.interval = Config[:evemond]['watch-interval']
37
+ log.backward(1)
38
+ log.tail do |line|
39
+ m = line.match(PKG_REGEXP)
40
+ next unless m
41
+
42
+ pkg = IPC::Data::Package.new(
43
+ name: m[:package],
44
+ version: m[:version],
45
+ command: m[:command]
46
+ )
47
+ @queue << pkg
48
+ Log.debug 'Arch package watcher enqued:', pkg
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def stop
55
+ @thr.exit
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,2 @@
1
+ require_relative './arch/package_watcher.rb'
2
+ require_relative './arch/package_manager.rb'
@@ -0,0 +1,80 @@
1
+ require 'hashdiff'
2
+ require 'evesync/ipc/data/package'
3
+
4
+ module Evesync
5
+ module OS
6
+ module BasePackageManager
7
+ def initialize
8
+ @packages = make_pkg_snapshot
9
+ end
10
+
11
+ def changes
12
+ # make hash of all packages
13
+ snapshot = make_pkg_snapshot
14
+ # diff with last version
15
+ diff = HashDiff.diff(@packages, snapshot)
16
+ # parse changes into IPC::Data::Package array
17
+ packages = parse_pkg_diff(diff)
18
+ # use new hash as default
19
+ # FIXME: wait if the changes were saved
20
+ # and properly handled
21
+ @packages = snapshot
22
+ packages
23
+ end
24
+
25
+ private
26
+
27
+ # Parses changes, given by 'hashdiff' gem into
28
+ # IPC::Data::Package array
29
+ def parse_pkg_diff(diffs)
30
+ packages = []
31
+ diffs.each do |diff|
32
+ package = case diff[0]
33
+ when '-' then removed_package(diff)
34
+ when '+' then installed_package(diff)
35
+ when '~' then updated_package(diff)
36
+ end
37
+ packages.push(package)
38
+ end
39
+
40
+ packages
41
+ end
42
+
43
+ def removed_package(diff)
44
+ IPC::Data::Package.new(
45
+ name: diff[1],
46
+ version: diff[2],
47
+ command: IPC::Data::Package::Command::REMOVE
48
+ )
49
+ end
50
+
51
+ def installed_package(diff)
52
+ IPC::Data::Package.new(
53
+ name: diff[1],
54
+ version: diff[2],
55
+ command: IPC::Data::Package::Command::INSTALL
56
+ )
57
+ end
58
+
59
+ def updated_package(diff)
60
+ command = if pkg_version_less(diff[2], diff[3])
61
+ IPC::Data::Package::Command::UPDATE
62
+ else
63
+ IPC::Data::Package::Command::DOWNGRADE
64
+ end
65
+
66
+ IPC::Data::Package.new(
67
+ name: diff[1],
68
+ version: diff[3],
69
+ command: command
70
+ )
71
+ end
72
+
73
+ # FIXME:
74
+ # - research about restrictions and make sure this work
75
+ def pkg_version_less(a, b)
76
+ a < b
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,30 @@
1
+ require 'hashdiff'
2
+ require 'evesync/log'
3
+ require 'evesync/os/linux/base_package_manager'
4
+
5
+ module Evesync
6
+ module OS
7
+ class Dpkg
8
+ include BasePackageManager
9
+
10
+ PKG_QUERY = 'dpkg-query -l'.freeze
11
+
12
+ private_constant :PKG_QUERY
13
+
14
+ # Snapshot is a hash where key is a package name
15
+ # and value - it's version.
16
+ # This function returns a snapshot of a system
17
+ # package status for a moment
18
+ def make_pkg_snapshot
19
+ snapshot = {}
20
+ query_output = `#{PKG_QUERY}`
21
+ query_output.lines.each do |line|
22
+ info = line.split
23
+ snapshot[info[1]] = info[2]
24
+ end
25
+
26
+ snapshot
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,38 @@
1
+ module Evesync
2
+ module OS
3
+ module PackageManager
4
+ class << self
5
+ def install(*args)
6
+ apt_get('install', *args)
7
+ exist?(*args)
8
+ end
9
+
10
+ def remove(*args)
11
+ apt_get('remove', *args)
12
+ !exist?(*args)
13
+ end
14
+
15
+ def update(*args)
16
+ apt_get('upgrade', *args)
17
+ exist?(*args)
18
+ end
19
+
20
+ def downgrade(*args)
21
+ apt_get('install', *args)
22
+ exist?(*args)
23
+ end
24
+
25
+ def apt_get(cmd, name, version)
26
+ Log.debug("Apt-get command: '#{cmd}' on #{name}=#{version}")
27
+ system("apt-get --assume-yes #{cmd} #{name}=#{version}")
28
+ end
29
+
30
+ def exist?(name, version)
31
+ Log.debug("Dpkg checking if exists: #{name}-#{version}")
32
+ `dpkg-query -l #{name}`
33
+ $CHILD_STATUS == 0
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,32 @@
1
+ require 'evesync/log'
2
+ require 'evesync/watcher/interface'
3
+ require_relative './dpkg'
4
+
5
+ module Evesync
6
+ module OS
7
+ class PackageWatcher < Watcher::Interface
8
+ def initialize(queue)
9
+ @queue = queue
10
+ @dpkg = Dpkg.new
11
+ Log.debug('Debian Package watcher initialized')
12
+ end
13
+
14
+ def start
15
+ Log.debug('Debian Package watcher started')
16
+ @thr = Thread.new do
17
+ loop do
18
+ sleep 10
19
+ @dpkg.changes.each do |pkg|
20
+ @queue << pkg
21
+ Log.debug 'Debian Package watcher enqued:', pkg
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def stop
28
+ @thr.exit
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,2 @@
1
+ require_relative './deb/package_watcher.rb'
2
+ require_relative './deb/package_manager.rb'
@@ -0,0 +1,42 @@
1
+ require 'evesync/log'
2
+
3
+ # Manages package manager things
4
+ # TODO: trigger package_watcher event to update database
5
+ module Evesync
6
+ module OS
7
+ module PackageManager
8
+ class << self
9
+ def install(*args)
10
+ return false if exist?(*args)
11
+ yum('install', *args)
12
+ exist?(*args)
13
+ end
14
+
15
+ def remove(*args)
16
+ yum('remove', *args)
17
+ !exist?(*args)
18
+ end
19
+
20
+ def update(*args)
21
+ yum('update', *args)
22
+ exist?(*args)
23
+ end
24
+
25
+ def downgrade(*args)
26
+ yum('downgrade', *args)
27
+ exist?(*args)
28
+ end
29
+
30
+ def yum(cmd, name, version)
31
+ Log.debug("Yum command: '#{cmd}' on #{name}-#{version}")
32
+ system("yum --assumeyes #{cmd} #{name}-#{version}")
33
+ end
34
+
35
+ def exist?(name, version)
36
+ Log.debug("Yum checking if exists: #{name}-#{version}")
37
+ system("rpm -q #{name}-#{version} >/dev/null 2>&1")
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ require_relative './rpm'
2
+ require 'evesync/log'
3
+ require 'evesync/watcher/interface'
4
+
5
+ module Evesync
6
+ module OS
7
+ class PackageWatcher < Watcher::Interface
8
+ def initialize(queue)
9
+ @queue = queue
10
+ @rpm_packages = Rpm.new
11
+ Log.debug('Rhel Package watcher initialized')
12
+ end
13
+
14
+ def start
15
+ Log.debug('Rhel Package watcher started')
16
+ @thr = Thread.new do
17
+ loop do
18
+ sleep 10 # FIXME: don't use magic numbers
19
+ @rpm_packages.changes.each do |pkg|
20
+ @queue << pkg
21
+ Log.debug 'Rhel Package watcher enqued:', pkg
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def stop
28
+ @thr.exit
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,41 @@
1
+ require 'evesync/log'
2
+ require 'evesync/os/linux/base_package_manager'
3
+
4
+ module Evesync
5
+ module OS
6
+
7
+ # Rpm packages changes watcher. Yum history makes it
8
+ # difficult to handler package removals. So, rpm is
9
+ # the only tool that show all packages in the system.
10
+ # This class handles packages changes.
11
+ #
12
+ # = Example:
13
+ # rpm = Evesync::Rpm.new
14
+ # sleep 1000
15
+ # rpm.changed.each do |package|
16
+ # p package # print packages that changed
17
+ # end
18
+ #
19
+ # = TODO:
20
+ # * add reinstall handling also
21
+ #
22
+ class Rpm
23
+ include BasePackageManager
24
+ # Query for rpm list
25
+ PKG_QUERY = 'rpm -qa --queryformat "%{NAME} %{VERSION}-%{RELEASE}.%{ARCH}\n"'.freeze
26
+
27
+ private_constant :PKG_QUERY
28
+
29
+ def make_pkg_snapshot
30
+ snapshot = {}
31
+ query_output = `#{PKG_QUERY}`
32
+ query_output.lines.each do |line|
33
+ info = line.split
34
+ snapshot[info[0]] = info[1]
35
+ end
36
+
37
+ snapshot
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ # TODO: add check if rpm exists
2
+ require_relative './rhel/package_watcher.rb'
3
+ require_relative './rhel/package_manager.rb'
@@ -0,0 +1,9 @@
1
+ text = File.new('/etc/os-release').read
2
+
3
+ if text =~ /^ID.*(rhel|centos|fedora)/
4
+ require 'evesync/os/linux/rhel'
5
+ elsif text =~ /ID.*arch/
6
+ require 'evesync/os/linux/arch'
7
+ elsif text =~ /ID.*debian/
8
+ require 'evesync/os/linux/deb'
9
+ end
data/lib/evesync/os.rb ADDED
@@ -0,0 +1,2 @@
1
+ # TODO: Fix to catch different OSes
2
+ require 'evesync/os/linux'