Skip to content

Commit

Permalink
Merge branch '2330-uptime-gets-computed-twice-on-systems-with-/proc/u…
Browse files Browse the repository at this point in the history
…ptime' into next
  • Loading branch information
Rein Henrichs committed Aug 4, 2010
2 parents 1bd2ca2 + a2bcacd commit 2b13972
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 37 deletions.
31 changes: 17 additions & 14 deletions lib/facter/uptime.rb
@@ -1,20 +1,23 @@
require 'facter/util/uptime'

Facter.add(:uptime) do
confine :operatingsystem => %w{Solaris Linux Fedora RedHat CentOS SuSE SLES Debian Ubuntu Gentoo AIX}
setcode do
Facter::Util::Uptime.get_uptime_simple
end
end
setcode do
seconds = Facter.fact(:uptime_seconds).value

if FileTest.exists?("/proc/uptime")
uptime = Facter::Util::Uptime.get_uptime
unless seconds
"unknown"
else
days = seconds / (60 * 60 * 24)
hours = seconds / (60 * 60) % 24
minutes = seconds / 60 % 60

%w{days hours seconds}.each do |label|
Facter.add("uptime_" + label) do
setcode do
Facter::Util::Uptime.get_uptime_period(uptime, label)
end
end
end
case days
when 0 then "#{hours}:#{"%02d" % minutes} hours"
when 1 then '1 day'
else "#{days} days"
end
end

end
end

7 changes: 7 additions & 0 deletions lib/facter/uptime_days.rb
@@ -0,0 +1,7 @@
Facter.add(:uptime_days) do
setcode do
hours = Facter.value(:uptime_hours)
hours && hours / 24 # hours in day
end
end

7 changes: 7 additions & 0 deletions lib/facter/uptime_hours.rb
@@ -0,0 +1,7 @@
Facter.add(:uptime_hours) do
setcode do
seconds = Facter.value(:uptime_seconds)
seconds && seconds / (60 * 60) # seconds in hour
end
end

10 changes: 10 additions & 0 deletions lib/facter/uptime_seconds.rb
@@ -0,0 +1,10 @@
require 'facter/util/uptime'

Facter.add(:uptime_seconds) do
setcode { Facter::Util::Uptime.get_uptime_seconds_unix }
end

Facter.add(:uptime_seconds) do
confine :kernel => :windows
setcode { Facter::Util::Uptime.get_uptime_seconds_win }
end
66 changes: 43 additions & 23 deletions lib/facter/util/uptime.rb
@@ -1,32 +1,52 @@
require 'time'

# A module to gather uptime facts
#
module Facter::Util::Uptime
def self.get_uptime_simple
time = Facter::Util::Resolution.exec('uptime')
if time =~ /up\s*(\d+\s\w+)/
$1
elsif time =~ /up\s*(\d+:\d+)/
$1 + " hours"
else
"unknown"
def self.get_uptime_seconds_unix
uptime_proc_uptime or uptime_sysctl or uptime_who_dash_b
end

def self.get_uptime_seconds_win
require 'Win32API'
getTickCount = Win32API.new("kernel32", "GetTickCount", nil, 'L')
compute_uptime(Time.at(getTickCount.call() / 1000.0))
end

private

def self.uptime_proc_uptime
if File.exists? uptime_file
r = File.read uptime_file
r.split(" ").first.to_i
end
end

def self.uptime_sysctl
if (output = `#{uptime_sysctl_cmd}`) and $?.success?
compute_uptime(Time.at(output.unpack('L').first))
end
end

def self.uptime_who_dash_b
if (output = `#{uptime_who_cmd}`) and $?.success?
compute_uptime(Time.parse(output))
end
end

def self.get_uptime
r = IO.popen("/bin/cat /proc/uptime")
uptime, idletime = r.readline.split(" ")
r.close
uptime_seconds = uptime.to_i
def self.compute_uptime(time)
(Time.now - time).to_i
end

def self.uptime_file
"/proc/uptime"
end

def self.uptime_sysctl_cmd
'sysctl -b kern.boottime 2>/dev/null'
end

def self.get_uptime_period(seconds, label)
case label
when 'days'
value = seconds / 86400
when 'hours'
value = seconds / 3600
when 'seconds'
seconds
end
def self.uptime_who_cmd
'who -b 2>/dev/null'
end
end
end
Binary file added spec/fixtures/uptime/sysctl_kern_boottime
Binary file not shown.
1 change: 1 addition & 0 deletions spec/fixtures/uptime/ubuntu_proc_uptime
@@ -0,0 +1 @@
5097686.63 40756306.43
1 change: 1 addition & 0 deletions spec/fixtures/uptime/who_b_boottime
@@ -0,0 +1 @@
reboot ~ Aug 1 14:13
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
@@ -1,5 +1,7 @@
dir = File.expand_path(File.dirname(__FILE__))

SPECDIR = dir

$LOAD_PATH.unshift("#{dir}/")
$LOAD_PATH.unshift("#{dir}/../lib")

Expand Down
112 changes: 112 additions & 0 deletions spec/unit/uptime.rb
@@ -0,0 +1,112 @@
#!/usr/bin/env ruby

require File.dirname(__FILE__) + '/../spec_helper'

require 'facter'
require 'facter/util/uptime'

describe "uptime facts:" do
before { Facter.clear }
after { Facter.clear }

context "when uptime information is available" do
describe "uptime" do
test_cases = [
[60 * 60 * 24 * 3, '3 days'],
[60 * 60 * 24 * 3 + 25, '3 days'],
[60 * 60 * 24 * 1, '1 day'],
[60 * 60 * 24 * 1 + 25, '1 day'],
[60 * (60 * 3 + 45), '3:45 hours'],
[60 * (60 * 3 + 4), '3:04 hours'],
[60 * 60, '1:00 hours'],
[60 * 35, '0:35 hours']
]

test_cases.each do |seconds, expected|
it "should return #{expected.inspect} for #{seconds} seconds" do
Facter::Util::Uptime.stubs(:get_uptime_seconds_unix).returns(seconds)
Facter::Util::Uptime.stubs(:get_uptime_seconds_win).returns(seconds)

Facter.fact(:uptime).value.should == expected
end
end
end

end

context "when uptime information is available" do
before do
Facter::Util::Uptime.stubs(:get_uptime_seconds_unix).returns(60 * 60 * 24 + 23)
Facter::Util::Uptime.stubs(:get_uptime_seconds_win).returns(60 * 60 * 24 + 23)
end

describe "uptime_seconds" do
it "should return the uptime in seconds" do
Facter.fact(:uptime_seconds).value.should == 60 * 60 * 24 + 23
end
end

describe "uptime_hours" do
it "should return the uptime in hours" do
Facter.fact(:uptime_hours).value.should == 24
end
end

describe "uptime_days" do
it "should return the uptime in days" do
Facter.fact(:uptime_days).value.should == 1
end
end
end

context "when uptime information is not available" do
before do
Facter::Util::Uptime.stubs(:get_uptime_seconds_unix).returns(nil)
Facter::Util::Uptime.stubs(:get_uptime_seconds_win).returns(nil)
$stderr, @old = StringIO.new, $stderr
end

after do
$stderr = @old
end

describe "uptime" do
it "should return 'unknown'" do
Facter.fact(:uptime).value.should == "unknown"
end
end

describe "uptime_seconds" do
it "should return nil" do
Facter.fact(:uptime_seconds).value.should == nil
end

it "should not print a warn message to stderr" do
Facter.fact(:uptime_seconds).value
$stderr.string.should == ""
end
end

describe "uptime_hours" do
it "should return nil" do
Facter.fact(:uptime_hours).value.should == nil
end

it "should not print a warn message to stderr" do
Facter.fact(:uptime_hours).value
$stderr.string.should == ""
end
end

describe "uptime_days" do
it "should return nil" do
Facter.fact(:uptime_days).value.should == nil
end

it "should not print a warn message to stderr" do
Facter.fact(:uptime_days).value
$stderr.string.should == ""
end
end
end
end
53 changes: 53 additions & 0 deletions spec/unit/util/uptime.rb
@@ -0,0 +1,53 @@
#!/usr/bin/env ruby

require File.dirname(__FILE__) + '/../../spec_helper'

require 'facter/util/uptime'

describe Facter::Util::Uptime do

describe ".get_uptime_seconds_unix" do
context "when /proc/uptime is available" do
before do
uptime_file = File.join(SPECDIR, "fixtures", "uptime", "ubuntu_proc_uptime")
Facter::Util::Uptime.stubs(:uptime_file).returns(uptime_file)
end

it "should return the uptime in seconds as an integer" do
Facter::Util::Uptime.get_uptime_seconds_unix.should == 5097686
end

end

it "should use sysctl kern.boottime when /proc/uptime not available" do
nonexistent_file = '/non/existent/file'
File.exists?(nonexistent_file).should == false
Facter::Util::Uptime.stubs(:uptime_file).returns(nonexistent_file)
sysctl_output_file = File.join(SPECDIR, 'fixtures', 'uptime', 'sysctl_kern_boottime') # Aug 01 14:13:47 -0700 2010
Facter::Util::Uptime.stubs(:uptime_sysctl_cmd).returns("cat #{sysctl_output_file}")
Time.stubs(:now).returns Time.parse("Aug 01 15:13:47 -0700 2010") # one hour later
Facter::Util::Uptime.get_uptime_seconds_unix.should == 60 * 60
end

it "should use who -b when neither /proc/uptime nor sysctl kern.boottime is available" do
nonexistent_file = '/non/existent/file'
File.exists?(nonexistent_file).should == false
Facter::Util::Uptime.stubs(:uptime_file).returns(nonexistent_file)
Facter::Util::Uptime.stubs(:uptime_sysctl_cmd).returns("cat #{nonexistent_file}")
who_b_output_file = File.join(SPECDIR, 'fixtures', 'uptime', 'who_b_boottime') # Aug 1 14:13
Facter::Util::Uptime.stubs(:uptime_who_cmd).returns("cat #{who_b_output_file}")
Time.stubs(:now).returns Time.parse("Aug 01 15:13") # one hour later
Facter::Util::Uptime.get_uptime_seconds_unix.should == 60 * 60
end

it "should return nil when none of /proc/uptime, sysctl kern.boottime, or who -b is available" do
nonexistent_file = '/non/existent/file'
File.exists?(nonexistent_file).should == false
Facter::Util::Uptime.stubs(:uptime_file).returns(nonexistent_file)
Facter::Util::Uptime.stubs(:uptime_sysctl_cmd).returns("cat #{nonexistent_file}")
Facter::Util::Uptime.stubs(:uptime_who_cmd).returns("cat #{nonexistent_file}")
Facter::Util::Uptime.get_uptime_seconds_unix.should == nil
end
end

end

0 comments on commit 2b13972

Please sign in to comment.