istat 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,78 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
6
+ <title>Top Level Namespace</title>
7
+ <link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
8
+ <link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
9
+
10
+ <script type="text/javascript" charset="utf-8">
11
+ relpath = '';
12
+ if (relpath != '') relpath += '/';
13
+ </script>
14
+ <script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
15
+ <script type="text/javascript" charset="utf-8" src="js/app.js"></script>
16
+
17
+ </head>
18
+ <body>
19
+ <script type="text/javascript" charset="utf-8">
20
+ if (window.top.frames.main) document.body.className = 'frames';
21
+ </script>
22
+
23
+ <div id="header">
24
+ <div id="menu">
25
+
26
+ <a href="_index.html">Index</a> &raquo;
27
+
28
+
29
+ <span class="title">Top Level Namespace</span>
30
+
31
+
32
+ <div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
33
+ </div>
34
+
35
+ <div id="search">
36
+ <a id="class_list_link" href="#">Class List</a>
37
+ <a id="method_list_link" href="#">Method List</a>
38
+ <a id ="file_list_link" href="#">File List</a>
39
+ </div>
40
+
41
+ <div class="clear"></div>
42
+ </div>
43
+
44
+ <iframe id="search_frame"></iframe>
45
+
46
+ <div id="content"><h1>Top Level Namespace
47
+
48
+
49
+
50
+ </h1>
51
+
52
+ <dl class="box">
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+ </dl>
62
+ <div class="clear"></div>
63
+
64
+
65
+
66
+
67
+
68
+
69
+ </div>
70
+
71
+ <div id="footer">
72
+ Generated on Fri Apr 29 23:16:07 2011 by
73
+ <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
74
+ 0.6.8 (ruby-1.8.7).
75
+ </div>
76
+
77
+ </body>
78
+ </html>
data/istat.gemspec ADDED
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push('lib')
3
+ require "istat/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "istat"
7
+ s.version = Istat::VERSION.dup
8
+ s.date = "2011-04-29"
9
+ s.summary = "an istat client library for ruby"
10
+ s.email = "vilandgr+github@googlemail.com"
11
+ s.homepage = "https://github.com/threez/istat"
12
+ s.authors = ['Vincent Landgaf']
13
+
14
+ s.description = <<-EOF
15
+ an istat client library for ruby
16
+ EOF
17
+
18
+ dependencies = [
19
+ # Examples:
20
+ # [:runtime, "rack", "~> 1.1"],
21
+ [:development, "rspec", "~> 2.1"],
22
+ ]
23
+
24
+ s.files = Dir['**/*']
25
+ s.test_files = Dir['spec/**/*']
26
+ s.executables = Dir['bin/*'].map { |f| File.basename(f) }
27
+ s.require_paths = ["lib"]
28
+
29
+
30
+ ## Make sure you can build the gem on older versions of RubyGems too:
31
+ s.rubygems_version = "1.6.1"
32
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
33
+ s.specification_version = 3 if s.respond_to? :specification_version
34
+
35
+ dependencies.each do |type, name, version|
36
+ if s.respond_to?("add_#{type}_dependency")
37
+ s.send("add_#{type}_dependency", name, version)
38
+ else
39
+ s.add_dependency(name, version)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,158 @@
1
+ require "socket"
2
+
3
+ # Copyright (c) 2011 Vincent Landgraf
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ module Istat
23
+ class Client
24
+ class WrongPasswordException < Exception; end
25
+ class NoServiceException < Exception; end
26
+ class RegisterException < Exception; end
27
+
28
+ # the frame that was send from the server after registration
29
+ attr_accessor :connection_frame
30
+
31
+ # create a new istat client instance
32
+ # @param host [String] the hostname of the remote istat server
33
+ # @param port [String] the port of the istat server usually 5109
34
+ # @param passwd [String] the passwd or code to access the server
35
+ # @param logger [optional Logger] a logger that will log all actions on the client
36
+ # @example
37
+ # @client = Istat::Clinet.new("example.com", 5109, "00000")
38
+ #
39
+ def initialize(host, port, passwd, logger = nil)
40
+ @host, @port, @passwd, @logger = host, port, passwd, logger
41
+ @request_id = 1
42
+ end
43
+
44
+ # starts a session on the remote machine and yields it to the passed block.
45
+ # @yield [Istat::Client] the remote session
46
+ # @example
47
+ # @client = Istat::Clinet.new("example.com", 5109, "00000")
48
+ # @client.start do |session|
49
+ # # work with the session
50
+ # end
51
+ #
52
+ def start
53
+ connect!
54
+ if online?
55
+ if register!
56
+ if authenticate!
57
+ yield(self)
58
+ else
59
+ raise WrongPasswordException.new("Wrong password/code!")
60
+ end
61
+ else
62
+ raise RegisterException.new("Can't register to the service")
63
+ end
64
+ else
65
+ raise NoServiceException.new("Service is not available")
66
+ end
67
+ close!
68
+ end
69
+
70
+ # connect to the remote server
71
+ # @return [Boolean] true is the connection was successfull
72
+ def connect!
73
+ @logger.info "Connect to #{@host}:#{@port}" if @logger
74
+ @socket = TCPSocket.new(@host, @port)
75
+ true
76
+ end
77
+
78
+ # authenticate using the password, that was passed during initialization
79
+ # @note must be connected and registered to the remote machine
80
+ # @return [Boolean] true on success
81
+ def authenticate!
82
+ @logger.info "Authenticate using password #{'*' * @passwd.size}" if @logger
83
+ send Istat::Frames::AuthenticationRequest.new(@passwd)
84
+ response = Istat::Frames::AuthenticationResponse.new(receive)
85
+ response.ready?
86
+ end
87
+
88
+ # checks if the host has the istat service active
89
+ # @note must be connected to the remote machine
90
+ # @return true on success
91
+ def online?
92
+ @logger.info "Test the connection" if @logger
93
+ send Istat::Frames::ConnectionTestRequest.new
94
+ response = Istat::Frames::ConnectionTestResponse.new(receive)
95
+ response.success?
96
+ end
97
+
98
+ # closes the connection
99
+ # @return true on success
100
+ def close!
101
+ @logger.info "Close the connection" if @logger
102
+ @socket.close
103
+ true
104
+ end
105
+
106
+ # register to the remote server using the source hostname and a uuid. If
107
+ # no values are passed, they will be fetched usind system methods. (Socket.gethostname)
108
+ # @note must be connected before this action should be called
109
+ # @param [optional, String] hostname the hostname for the registration (e.g. example.com)
110
+ # @param [optional, String] duuid the uuid for the registration
111
+ def register!(hostname = nil, duuid = nil)
112
+ hostname ||= Socket.gethostname
113
+ duuid ||= Istat::Utils.uuid
114
+ @logger.info "Register using hostname '#{hostname}' and duuid '#{duuid}'" if @logger
115
+ send Istat::Frames::RegisterRequest.new(hostname, duuid)
116
+ @connection_frame = Istat::Frames::RegisterResponse.new(receive)
117
+ end
118
+
119
+ # fetch data from the remote server
120
+ # @param [Integer|Time] since size of the requested history (-1 last)
121
+ # @return [Istat::Frames::MeasurementResponse] the fetched result
122
+ # @example
123
+ # @client = Istat::Clinet.new("example.com", 5109, "00000")
124
+ # @client.start do |session|
125
+ # response = session.fetch
126
+ # response.load # => [0.54, 0.59, 0.65]
127
+ # end
128
+ #
129
+ def fetch(since = -1)
130
+ @logger.info("Fetch measurements with request_id #{@request_id}")
131
+ send Istat::Frames::MeasurementRequest.new(@request_id, since)
132
+ @request_id += 1 # increment for next request
133
+ Istat::Frames::MeasurementResponse.new(receive)
134
+ end
135
+
136
+ protected
137
+
138
+ # send a frame to the remote system (istatd)
139
+ # @note will use the *to_s* method to serialize the frame on the wire
140
+ # @param [Istat::Frame::Request] the frame to send
141
+ # @return [Integer] number of bytes send
142
+ def send(frame)
143
+ @logger.debug "Send: #{frame.to_s}" if @logger
144
+ @socket.send frame.to_s, 0
145
+ end
146
+
147
+ # receive data for a frame from the remote system (istatd)
148
+ # @return [String] the xml stream that was send from istatd
149
+ def receive
150
+ data = ""
151
+ begin
152
+ data << @socket.recv(1024)
153
+ end while !data.include?("</isr>")
154
+ @logger.debug "Recieved: #{data}" if @logger
155
+ data
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright (c) 2011 Vincent Landgraf
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+ module Istat
21
+ module Frames
22
+ # authenticate with passwd
23
+ class AuthenticationRequest
24
+ # create a new authentication resquest frame with the passed code/password
25
+ # @param [String] password the password to use for authentication
26
+ def initialize(password)
27
+ @password = password
28
+ end
29
+
30
+ # just returns the password, the frame has no header or container
31
+ # @return [String] the password
32
+ def to_s
33
+ @password
34
+ end
35
+ end
36
+
37
+ class AuthenticationResponse < Response
38
+ READY = "ready".freeze
39
+ REJECT = "athrej".freeze
40
+
41
+ # check if he authentication was successful
42
+ # @return [Boolean] true if authentication is successful
43
+ def ready?
44
+ if val = @root.attributes[READY]
45
+ val.to_i == 1
46
+ else
47
+ false
48
+ end
49
+ end
50
+
51
+ # check if he authentication was rejected
52
+ # @return [Boolean] true if authentication is rejected
53
+ def rejected?
54
+ if val = @root.attributes[REJECT]
55
+ val.to_i == 1
56
+ else
57
+ false
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,60 @@
1
+ require "rexml/document"
2
+
3
+ # Copyright (c) 2011 Vincent Landgraf
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ module Istat
23
+ module Frames
24
+ # This class handles basic xml actions and content parsing for the frames
25
+ # @abstract
26
+ class Base
27
+ # xml doytype style header
28
+ DOCTYPE = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>".freeze
29
+
30
+ # creates a frame based on the passed xml string
31
+ # @param [String] xml_str the xml string to use for initalization
32
+ def initialize(xml_str)
33
+ @doc = REXML::Document.new(xml_str)
34
+ @root = @doc.root
35
+ end
36
+
37
+ # serialize the frame (as xml)
38
+ # @return [String] a xml structure
39
+ def to_s
40
+ @doc.to_s
41
+ end
42
+
43
+ protected
44
+
45
+ # create new frame (xml) based on the passed params
46
+ # @params [Array<Array>] the arrays on which the xml structure will be generated
47
+ # @return [String] the generated xml structure
48
+ # @api private
49
+ def create(*params)
50
+ xml = "#{DOCTYPE}<isr>"
51
+ params.each { |key, value| xml << "<#{key}>#{value}</#{key}>" }
52
+ xml << "</isr>"
53
+ xml
54
+ end
55
+ end
56
+
57
+ class Request < Base; end
58
+ class Response < Base; end
59
+ end
60
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2011 Vincent Landgraf
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+ module Istat
21
+ module Frames
22
+ class ConnectionTestRequest < Request
23
+ def initialize
24
+ super create([:conntest, nil])
25
+ end
26
+ end
27
+
28
+ class ConnectionTestResponse < Response
29
+ # check for an empty frame, that will be returned by the server
30
+ # @return [Boolean] ture if the connection was successful established
31
+ def success?
32
+ @root.to_a.empty?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,254 @@
1
+ # Copyright (c) 2011 Vincent Landgraf
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+ module Istat
21
+ module Frames
22
+ class MeasurementRequest < Request
23
+ RID = :rid
24
+ CPU = :c
25
+ NETWORK = :n
26
+ MEMORY = :m
27
+ LOAD = :lo
28
+ TEMP = :t # qnap only
29
+ FAN = :f
30
+ UPTIME = :u
31
+ DISK = :d
32
+
33
+ # create a new request based on the requested id. The default is to
34
+ # request only the last values (since -1)
35
+ # @param [Integer] rid the request identifier (increases)
36
+ # @param [Integer] since the since field (-1 for last, or Time.now timestamp)
37
+ def initialize(rid, since = -1)
38
+ since = Time.now.to_i - since.to_i if since.is_a? Time
39
+ super create([RID, rid],
40
+ [CPU, since],
41
+ [NETWORK, since],
42
+ [MEMORY, since],
43
+ [LOAD, since],
44
+ [TEMP, since],
45
+ [FAN, since],
46
+ [UPTIME, since],
47
+ [DISK, since])
48
+ end
49
+ end
50
+
51
+ class MeasurementResponse < Response
52
+ # returns true if there is a cpu section in the frame
53
+ def cpu?
54
+ has_node? :CPU
55
+ end
56
+
57
+ # collect cpu data (can contain history)
58
+ # @return [Array<Hash>] the cpu load and usage data
59
+ # @example Result
60
+ # [
61
+ # { :id => 28388970, :user => 0, :system => 0, :nice => 0 },
62
+ # { :id => 28388971, :user => 0, :system => 0, :nice => 0 },
63
+ # { :id => 28388972, :user => 0, :system => 0, :nice => 0 },
64
+ # { :id => 28388973, :user => 0, :system => 0, :nice => 0 }
65
+ # ]
66
+ def cpu
67
+ entires_for(:CPU) do |element, attributes|
68
+ {
69
+ :id => attributes["id"].to_i,
70
+ :user => attributes["u"].to_i,
71
+ :system => attributes["s"].to_i,
72
+ :nice => attributes["n"].to_i
73
+ }
74
+ end
75
+ end
76
+
77
+ # returns true if there is a network section in the frame
78
+ def network?
79
+ has_node? :NET
80
+ end
81
+
82
+ # collects all network information over the interfaces (can contain history)
83
+ # @return [Hash<Array<Hash>>] the network data for the interfaces
84
+ # @example Result
85
+ # {
86
+ # 1 => [
87
+ # { :id => 28388970, :d => 4177773, :u => 232278672, :t => 1304082088 },
88
+ # { :id => 28388971, :d => 4177773, :u => 232278672, :t => 1304082089 },
89
+ # { :id => 28388972, :d => 4177773, :u => 232278672, :t => 1304082090 },
90
+ # { :id => 28388973, :d => 4177773, :u => 232278672, :t => 1304082091 }
91
+ # ]
92
+ # }
93
+ #
94
+ def network
95
+ interfaces = { 1 => [] }
96
+ entires_for(:NET) do |element, attributes|
97
+ interfaces[1] << {
98
+ :id => attributes["id"].to_i,
99
+ :d => attributes["d"].to_i,
100
+ :u => attributes["u"].to_i,
101
+ :t => attributes["t"].to_i
102
+ }
103
+ end
104
+ interfaces
105
+ end
106
+
107
+ # returns true if there is a memory section in the frame
108
+ def memory?
109
+ has_node? :MEM
110
+ end
111
+
112
+ # parse the memory informations
113
+ # @return [Hash] the memory information
114
+ # @example Result
115
+ # {
116
+ # :wired => 25938,
117
+ # :active => 27620,
118
+ # :inactive => 11664,
119
+ # :free => 7983,
120
+ # :total => 73207,
121
+ # :swap_used => 3,
122
+ # :swap_total => 36861,
123
+ # :page_ins => 0,
124
+ # :page_outs => 0
125
+ # }
126
+ #
127
+ def memory
128
+ attributes = @root.elements["MEM"].attributes
129
+ {
130
+ :wired => attributes["w"].to_i,
131
+ :active => attributes["a"].to_i,
132
+ :inactive => attributes["i"].to_i,
133
+ :free => attributes["f"].to_i,
134
+ :total => attributes["t"].to_i,
135
+ :swap_used => attributes["su"].to_i,
136
+ :swap_total => attributes["st"].to_i,
137
+ :page_ins => attributes["pi"].to_i,
138
+ :page_outs => attributes["po"].to_i
139
+ }
140
+ end
141
+
142
+ # returns true if there is a load section in the frame
143
+ def load?
144
+ has_node? :LOAD
145
+ end
146
+
147
+ # parse the load informations
148
+ # @return [Array] the load of the system
149
+ # @example Result
150
+ # [0.54, 0.60, 0.67]
151
+ #
152
+ def load
153
+ attributes = @root.elements["LOAD"].attributes
154
+ [attributes["one"].to_f, attributes["fv"].to_f, attributes["ff"].to_f]
155
+ end
156
+
157
+ # returns true if there is a temps section in the frame
158
+ def temps?
159
+ has_node? :TEMPS
160
+ end
161
+
162
+ # collect all temperature informations in order
163
+ # @return [Array] the temps that are returned using the sensor modules
164
+ # @example
165
+ # [30, 52, 29, 50, 30, 64, 61]
166
+ #
167
+ def temps
168
+ temps = []
169
+ entires_for(:TEMPS) do |element, attributes|
170
+ temps[attributes["i"].to_i] = attributes["t"].to_i
171
+ end
172
+ temps
173
+ end
174
+
175
+ # returns true if there is a fan section in the frame
176
+ def fans?
177
+ has_node? :FANS
178
+ end
179
+
180
+ # collect all fan informations in order
181
+ # @return [Array] containing all the fans
182
+ # @example Result
183
+ # [1999]
184
+ #
185
+ def fans
186
+ fans = []
187
+ entires_for(:FANS) do |element, attributes|
188
+ fans[attributes["i"].to_i] = attributes["s"].to_i
189
+ end
190
+ fans
191
+ end
192
+
193
+ # returns true if there is a uptime section in the frame
194
+ def uptime?
195
+ has_node? :UPT
196
+ end
197
+
198
+ # calculate the system uptime
199
+ # @return [Time] the uptime orf the system
200
+ # @example Result
201
+ # "Sat Apr 30 09:46:45 +0200 2011"
202
+ #
203
+ def uptime
204
+ Time.now - @root.elements["UPT"].attributes["u"].to_i
205
+ end
206
+
207
+ # returns true if there is a disks section in the frame
208
+ def disks?
209
+ has_node? :DISKS
210
+ end
211
+
212
+ # collect all disk informations
213
+ # @return [Array<Hash>] all disks of the system
214
+ # @example Result
215
+ # [
216
+ # :label => "/",
217
+ # :uuid => "/dev/vzfs",
218
+ # :free => 9226,
219
+ # :percent_used => 39.931
220
+ # ]
221
+ #
222
+ def disks
223
+ entires_for(:DISKS) do |element, attributes|
224
+ {
225
+ :label => attributes["n"],
226
+ :uuid => attributes["uuid"],
227
+ :free => attributes["f"].to_i,
228
+ :percent_used => attributes["p"].to_f
229
+ }
230
+ end
231
+ end
232
+
233
+ protected
234
+
235
+ # returns true if a node is available
236
+ # @api private
237
+ def has_node?(name)
238
+ !@root.elements["#{name}"].nil?
239
+ end
240
+
241
+ # yields over the elements of a path
242
+ # @api private
243
+ def entires_for(name, &block)
244
+ entries = []
245
+ @root.elements["#{name}"].map do |element|
246
+ unless element.is_a? REXML::Text
247
+ entries << block.call(element, element.attributes)
248
+ end
249
+ end
250
+ entries
251
+ end
252
+ end
253
+ end
254
+ end