zombie_check 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4920ff896447270b5f95b172f733995e82a7fc8f
4
+ data.tar.gz: 5c7b2c79e3ad4e1ac2b160a4e92abdfe512cadbe
5
+ SHA512:
6
+ metadata.gz: b4429185406db8e6d1f8e0f7916192c9f814b7c82bff399b05fb75415f1e230fa4195f42ac7d18113164cf9d052b42546efeb4e17359e179fb7c2f5d5327f7de
7
+ data.tar.gz: 0ca9fb3648d8bc51dd0e91358960046071d2d20cd23d32544692ed8d99bd849ffc5398ee0ecdd94225ad9c096669246defb64928ad7dbc550449f08a4d34cfed
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /tmp/*
11
+ /.idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,58 @@
1
+ Style/AlignHash:
2
+ EnforcedHashRocketStyle: table
3
+ EnforcedColonStyle: table
4
+ AutoCorrect: true
5
+ Style/IndentationConsistency:
6
+ EnforcedStyle: rails
7
+ Style/StringLiterals:
8
+ ConsistentQuotesInMultiline: true
9
+ Metrics/ClassLength:
10
+ CountComments: false
11
+ Max: 500
12
+ Metrics/ModuleLength:
13
+ CountComments: false
14
+ Max: 500
15
+ Lint/EndAlignment:
16
+ AutoCorrect: true
17
+ Lint/DefEndAlignment:
18
+ AutoCorrect: true
19
+ Rails:
20
+ Enabled: false
21
+ Style/AutoResourceCleanup:
22
+ Description: 'Suggests the usage of an auto resource cleanup version of a method (if available).'
23
+ Enabled: true
24
+ Metrics/MethodLength:
25
+ CountComments: false # count full line comments?
26
+ Max: 40
27
+ Style/StringLiterals:
28
+ EnforcedStyle: double_quotes
29
+ ConsistentQuotesInMultiline: true
30
+ Style/StringLiteralsInInterpolation:
31
+ EnforcedStyle: single_quotes
32
+ NumericLiterals:
33
+ Enabled: false
34
+ Metrics/LineLength:
35
+ Max: 160
36
+ Documentation:
37
+ Enabled: false
38
+ Lint/Debugger: # Easy deletion of all debugger breakpoints. false for debug
39
+ Enabled: true
40
+ AllCops:
41
+ Exclude:
42
+ - 'bin/**/*'
43
+ - 'vendor/**/*'
44
+ - 'log/**/*'
45
+ - 'tmp/**/*'
46
+ TargetRubyVersion: 2.3
47
+ Metrics/AbcSize:
48
+ Max: 35
49
+ inherit_from: .rubocop_todo.yml
50
+ Metrics/CyclomaticComplexity:
51
+ Max: 10
52
+ Rails/HasAndBelongsToMany:
53
+ Enabled: false
54
+ Style/GlobalVars:
55
+ Description: 'Do not introduce global variables.'
56
+ StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#instance-vars'
57
+ Reference: 'http://www.zenspider.com/Languages/Ruby/QuickRef.html'
58
+ Enabled: false
data/.rubocop_todo.yml ADDED
File without changes
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.1
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+ source "https://rubygems.org"
3
+
4
+ # Specify your gem's dependencies in zombie_check.gemspec
5
+
6
+ gem "net-ping"
7
+
8
+ gemspec
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ ##Severs.com, тестовое задание
2
+
3
+ Нужно написать приложение:
4
+
5
+ Приложение имеет следующие вызовы:
6
+ 1) Добавить IP-адрес к подсчету статистики (параметр - IP-адрес, нотацию выбери сам)
7
+ 2) Удалить IP-адрес из подсчета статистики (параметр - IP-адрес, нотацию выбери сам)
8
+ 3) Сообщить статистику доступности IP-адреса по ICMP [то есть посредством ping] (параметры - IP-адрес, начало интервала времени, конец интервала времени). Получив начало и конец интервала времени, должно вернуть JSON, содержащий следующие поля:
9
+ - среднее RTT (время отклика на пинг) за этот период
10
+ - минимальное RTT за этот период
11
+ - максимальное RTT за этот период
12
+ - медианное RTT за этот период
13
+ - среднеквадратичное отклонение замеров RTT за этот период
14
+ - процент потерянных пакетов ICMP (ping) до указанного адреса за этот период.
15
+
16
+ Если какую-то часть времени в этом периоде IP-адрес был вне расчета статистики (не был добавлен или был удален) - эту часть времени учитывать не нужно. Например, мы добавили ip-адрес 8.8.8.8 в 1 час, выключили в 2, включили в 3 и выключили в 4. Если я запросил статистику с 1 по 4 часа — надо объединить интервалы 1-2, 3-4 и отдать эту статистику по объединенному интервалу. Если IP-адрес не был в расчете статистики все время или был настолько мало времени, что мы не успели сделать хотя бы 1 замер - надо вернуть сообщение об ошибке.
17
+
18
+ Соответственно, удаленные машины, имеющие IP-адреса из этого списка могут вести себя очень странно - не отвечать на пинги, отвечать с ооочень большой задержкой - например, минуту (если захочется поиграться с этим случаем, его можно смоделировать на машинке, поставив, например, Charles http://www.charlesproxy.com/documentation/proxying/throttling/ туда).
19
+
20
+ Задание может быть выполнено на разном уровне сложности - можно замахнуться на то, чтобы сделать идеально и таки научиться обрабатывать ситуации с пингом в минуту, или пытаться оптимизировать производительность - а можно не делать ничего из этого. Ты можешь пойти любым путем в зависимости от твоего свободного времени.
21
+
22
+ Ниже доступ в панель servers.com — там ты можешь завести сколько тебе понадобится для выполнение виртуалок в клауде под Linux или Windows (на случай если тебе нужна среда запуска приложения или баз данных или еще чего-то, а на своем компьютере почему-то ты этого делать не хочешь).
23
+
24
+ URL: http://portal.servers.com
25
+ Login: foo@servers.com
26
+ Password: xxx
27
+
28
+
29
+ ## Мои комментарии
30
+
31
+ Стартовать надо через sudo, ибо `net-ping` полключается напрямую к сокетам. Можно переколбасить на обычный ping, если критично.
32
+
33
+ В качестве интерфейса для хостов юзается фаил `hosts.txt` в корне. Но это можно переписать аргументами
34
+
35
+ Ранее не было проблем с запуском pry, да и sudo в реальсе не особо нужен. Словил прикольный момент,
36
+ который несколько смутил. Все шустро решилось, но все
37
+ же http://stackoverflow.com/questions/37458855/unix-sudo-pry-does-not-start
38
+
39
+ Charles умеет делать задержки для tcp или udp запросов, но вот ничего в настройках про icmp я так и не увидел. В любом случае буду признателен за тычек пальцем в нужную сторону.
40
+
41
+ Если убрать задержку в `zombie_check delay:0` (чтобы замутить попытку DOS через ping :) то потоки долго убиваются. Я пока что не нашел способа это ускорить. Как вариант приписать #join в 19й строке checker.rb, но тогда исчезает все веселье.
42
+
43
+ В данном виде, на бесконечном отрезке времени прога сожрет всю память. Я вкурсе, если это важно- поправлю.
44
+
45
+ Если нужны тесты- приделаю.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'zombie_check'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/bin/zombie_check ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+ require 'pry'
4
+
5
+ source_path = (Pathname.new(__FILE__).dirname + '../lib').expand_path
6
+ $LOAD_PATH << source_path
7
+
8
+ require 'zombie_check'
9
+
10
+ if ['-v', '--version'].include? ARGV[0]
11
+ puts "Version #{ZombieCheck::VERSION}"
12
+ exit 0
13
+ elsif ['-h', '--help'].include? ARGV[0]
14
+ puts 'You can specify options with syntax like option_name:value'
15
+ puts 'hosts_file - file with list of all hosts'
16
+ puts "delay - delay between pings in ms, default 1000 \n\n"
17
+ exit 0
18
+ end
19
+
20
+ options = {}.tap do |result|
21
+ ARGV.each do |argv|
22
+ split_args = argv.split ':'
23
+ result[split_args.first.to_sym] = split_args.last
24
+ end
25
+ end
26
+
27
+ ZombieCheck::Ping::Checker.new(options).start
data/hosts.txt ADDED
@@ -0,0 +1,5 @@
1
+ 127.0.0.1
2
+ 8.8.8.8
3
+ mail.ru
4
+ google.ru
5
+ ya.ru
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+ require "zombie_check/core_ext/ennumerable"
3
+ require "zombie_check/version"
4
+ require "zombie_check/ping/checker"
5
+ require "zombie_check/ping/checker_report"
6
+ require "net/ping"
7
+
8
+ module ZombieCheck
9
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+ module Enumerable
3
+ def sum
4
+ inject(0) { |accum, i| accum + i }
5
+ end
6
+
7
+ def mean
8
+ # rubocop bug, other way it dies https://github.com/bbatsov/rubocop/issues/3169
9
+ return -1 if send(:length) == 0
10
+ sum / length.to_f
11
+ end
12
+
13
+ def sigma
14
+ return -1 if length < 2
15
+ m = mean
16
+ sum = inject(0) { |accum, i| accum + (i - m)**2 }
17
+ Math.sqrt(sum / (length - 1).to_f)
18
+ end
19
+
20
+ def median
21
+ return -1 if send(:length) == 0
22
+ middle = length / 2
23
+ sorted = sort
24
+ length.even? ? (sorted[middle] + sorted[middle - 1]) / 2 : sorted[middle]
25
+ end
26
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+ module ZombieCheck
3
+ module Ping
4
+ class Checker
5
+ attr_accessor :hosts_file, :delay, :hosts, :report, :interrupted
6
+
7
+ def initialize(options = {})
8
+ @hosts_file ||= options[:hosts_file] || "hosts.txt"
9
+ @delay ||= (options[:delay] || 1000).to_i / 1000.0
10
+ @hosts ||= []
11
+ @report = CheckerReport.new
12
+ setup_interruptor
13
+ end
14
+
15
+ def start
16
+ puts "Using file #{hosts_file}, delay #{delay}, for exit press Ctrl+C"
17
+ loop do
18
+ update_hosts!
19
+ @hosts.each { |host| Thread.new { ping host } }
20
+ if interrupted
21
+ exit_all_threads!
22
+ puts @report.generate
23
+ exit 0
24
+ end
25
+ sleep @delay
26
+ end
27
+ end
28
+
29
+ def ping(host)
30
+ icmp = Net::Ping::ICMP.new(host)
31
+ icmp.ping
32
+ @report << icmp
33
+ end
34
+
35
+ private
36
+
37
+ def update_hosts!
38
+ check_file_exists! hosts_file_path
39
+ result = File.open(hosts_file_path, "r") { |f| f.readlines.map(&:chomp) }
40
+ check_result_not_empty! result
41
+ @hosts = result
42
+ end
43
+
44
+ def check_file_exists!(file)
45
+ return if File.exist?(file)
46
+ puts "No #{@hosts_file} file"
47
+ exit 0
48
+ end
49
+
50
+ def check_result_not_empty!(result)
51
+ return unless result.empty? && @hosts.empty?
52
+ puts "#{@hosts_file} is empty"
53
+ exit 0
54
+ end
55
+
56
+ def hosts_file_path
57
+ File.expand_path(@hosts_file)
58
+ end
59
+
60
+ def setup_interruptor
61
+ trap("INT") { @interrupted = true }
62
+ end
63
+
64
+ def exit_all_threads!
65
+ Thread.list.reject { |t| t == Thread.current }.each(&:exit)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ module ZombieCheck
3
+ module Ping
4
+ class CheckerReport
5
+ PRECISION = 3
6
+ attr_accessor :stat
7
+
8
+ def initialize
9
+ @stat ||= {}
10
+ end
11
+
12
+ def <<(ping)
13
+ host = @stat[ping.host] ||= {}
14
+ host[:durations] ||= []
15
+ host[:lost] ||= 0
16
+ if (ping_duration = ping.duration)
17
+ host[:durations] << (ping_duration * 1000).round(PRECISION)
18
+ else
19
+ host[:lost] += 1
20
+ end
21
+ end
22
+
23
+ def generate
24
+ [].tap do |result|
25
+ stat.each_pair do |host, log|
26
+ total = log[:durations].size + log[:lost]
27
+ percentage = total > 0 ? log[:lost] / total : 0
28
+
29
+ result << <<-REPORT
30
+
31
+ To #{host} total sent #{total} pings, lost #{log[:lost]} (#{percentage}%). Time(ms):
32
+ AVG #{log[:durations].mean.round(PRECISION)} MIN #{log[:durations].min} \
33
+ MAX #{log[:durations].max} sigma #{log[:durations].sigma.round(PRECISION)} \
34
+ median #{log[:durations].median.round(PRECISION)}
35
+ REPORT
36
+ end
37
+ end.join "\n"
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+ module ZombieCheck
3
+ VERSION = "0.1.0"
4
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+ lib = File.expand_path("../lib", __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "zombie_check/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "zombie_check"
9
+ spec.version = ZombieCheck::VERSION
10
+ spec.authors = ["Kvokka"]
11
+ spec.email = ["root_p@mail.ru"]
12
+
13
+ spec.summary = "Ping all from file list"
14
+ spec.description = "Ping all from file list"
15
+ spec.homepage = "https://github.com/kvokka/zombie_check"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.executables = ["zombie_check"]
19
+ spec.require_paths = ["lib"]
20
+ spec.license = "MIT"
21
+ spec.required_ruby_version = ">= 2.0.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.11"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "pry"
27
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zombie_check
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kvokka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Ping all from file list
70
+ email:
71
+ - root_p@mail.ru
72
+ executables:
73
+ - zombie_check
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".rubocop.yml"
80
+ - ".rubocop_todo.yml"
81
+ - ".travis.yml"
82
+ - Gemfile
83
+ - README.md
84
+ - Rakefile
85
+ - bin/console
86
+ - bin/setup
87
+ - bin/zombie_check
88
+ - hosts.txt
89
+ - lib/zombie_check.rb
90
+ - lib/zombie_check/core_ext/ennumerable.rb
91
+ - lib/zombie_check/ping/checker.rb
92
+ - lib/zombie_check/ping/checker_report.rb
93
+ - lib/zombie_check/version.rb
94
+ - zombie_check.gemspec
95
+ homepage: https://github.com/kvokka/zombie_check
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 2.0.0
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.5.1
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Ping all from file list
119
+ test_files: []
120
+ has_rdoc: