istat 0.0.1

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.
@@ -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