carnac 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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ # Carnac - Hard Drive Failure Prediction Tool
2
+
3
+ ## Usage
4
+
5
+ ```
6
+ $> gem install carnac
7
+ $> carnac -d DEVICE
8
+ ```
9
+
10
+ ## License
11
+
12
+ (MIT License) - Copyright (c) 2012 Michael Pellon
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/carnac ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'carnac'
7
+ require 'optparse'
8
+
9
+ ARGV << '--help' if ARGV.empty?
10
+
11
+ options = {}
12
+ OptionParser.new do |opts|
13
+ opts.banner = "Usage: carnac [options]"
14
+
15
+ opts.on("-d", "--device PATH", String, "The path to the device to be checked") do |v|
16
+ options[:device] = v
17
+ end
18
+
19
+ opts.on("-n", "--notify EMAIL", String, "The email address to send notifications to") do |v|
20
+ options[:notify] = v
21
+ end
22
+
23
+ opts.on("-x", "-- EMAIL", String, "") do |v|
24
+ options[:notify] = v
25
+ end
26
+ end.parse!
27
+
28
+ Carnac::Check.new(options).run!
data/carnac.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "carnac/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "carnac"
7
+ s.version = Carnac::VERSION
8
+ s.authors = ["Michael Pellon"]
9
+ s.email = ["michael@p3ll0n.net"]
10
+ s.homepage = "https://github.com/p3ll0n/carnac"
11
+ s.summary = "Implementation of simple hard drive failure prediction heuristic"
12
+ s.description = s.summary
13
+
14
+ s.rubyforge_project = "carnac"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
data/lib/carnac.rb ADDED
@@ -0,0 +1,2 @@
1
+ require "carnac/version"
2
+ require "carnac/check"
@@ -0,0 +1,71 @@
1
+ require 'net/smtp'
2
+ require 'socket'
3
+
4
+ module Carnac
5
+
6
+ class Check
7
+ def initialize(options)
8
+ @device = options.delete(:device) || '/dev/sda'
9
+ @notify = options.delete(:notify) || ''
10
+ @flags = options.delete(:flags) || ''
11
+ @hostname = Socket.gethostname
12
+ end
13
+
14
+ def send_email(to,opts={})
15
+ opts[:server] ||= "localhost"
16
+ opts[:from] ||= "carnac@#{@hostname}"
17
+ opts[:subject] ||= "[#{@hostname}] - Hard Drive Failure Predicted!"
18
+ opts[:body] ||= ""
19
+
20
+ msg = <<END_OF_MESSAGE
21
+ From: #{opts[:from_alias]} <#{opts[:from]}>
22
+ To: <#{to}>
23
+ Subject: #{opts[:subject]}
24
+
25
+ #{opts[:body]}
26
+ END_OF_MESSAGE
27
+
28
+ Net::SMTP.start(opts[:server]) do |smtp|
29
+ smtp.send_message msg, opts[:from], to
30
+ end
31
+ end
32
+
33
+ def field_by_header(header_row, data_row, key)
34
+ pos = header_row.index key
35
+ data_row[pos..-1].split(' ').first
36
+ end
37
+
38
+ def run!
39
+ if @flags.empty?
40
+ lines = `smartctl -a #{@device}`.split("\n")
41
+ else
42
+ lines = `smartctl -a #{@flags} #{@device}`.split("\n")
43
+ end
44
+
45
+ header = lines.grep(/^ID#/).first
46
+ header_idx = lines.index header
47
+
48
+ data = {}
49
+ lines[header_idx+1..-1].each do |row|
50
+ break if row.empty?
51
+ key = field_by_header(header, row, 'ATTRIBUTE_NAME')
52
+ value = field_by_header(header, row, 'RAW_VALUE')
53
+ data[key] = value
54
+ end
55
+
56
+ if data.values_at(*%w(Reallocated_Sector_Ct Current_Pending_Sector)).any?
57
+ msg = "#{@device}: #{data['Airflow_Temperature_Cel']}°C, #{data['Reallocated_Sector_Ct']} sector reallocations"
58
+ if data['Current_Pending_Sector'] && Integer(data['Current_Pending_Sector']) > 0
59
+ msg << " (#{data['Current_Pending_Sector']} pending)"
60
+ end
61
+ if @notify.empty?
62
+ send_email "#{@notify}", :body => msg
63
+ else
64
+ puts msg
65
+ end
66
+ end
67
+
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,3 @@
1
+ module Carnac
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: carnac
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael Pellon
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-27 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Implementation of simple hard drive failure prediction heuristic
15
+ email:
16
+ - michael@p3ll0n.net
17
+ executables:
18
+ - carnac
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - README.md
25
+ - Rakefile
26
+ - bin/carnac
27
+ - carnac.gemspec
28
+ - lib/carnac.rb
29
+ - lib/carnac/check.rb
30
+ - lib/carnac/version.rb
31
+ homepage: https://github.com/p3ll0n/carnac
32
+ licenses: []
33
+ post_install_message:
34
+ rdoc_options: []
35
+ require_paths:
36
+ - lib
37
+ required_ruby_version: !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ! '>='
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project: carnac
51
+ rubygems_version: 1.8.24
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: Implementation of simple hard drive failure prediction heuristic
55
+ test_files: []
56
+ has_rdoc: