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.
- data/README.md +57 -0
- data/debug.log +181 -0
- data/doc/_index.html +82 -0
- data/doc/class_list.html +36 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +53 -0
- data/doc/css/style.css +318 -0
- data/doc/file.README.html +99 -0
- data/doc/file_list.html +38 -0
- data/doc/frames.html +13 -0
- data/doc/index.html +99 -0
- data/doc/js/app.js +203 -0
- data/doc/js/full_list.js +149 -0
- data/doc/js/jquery.js +16 -0
- data/doc/method_list.html +35 -0
- data/doc/top-level-namespace.html +78 -0
- data/istat.gemspec +42 -0
- data/lib/istat/client.rb +158 -0
- data/lib/istat/frames/authentication.rb +62 -0
- data/lib/istat/frames/base.rb +60 -0
- data/lib/istat/frames/connection_test.rb +36 -0
- data/lib/istat/frames/measurement.rb +254 -0
- data/lib/istat/frames/register.rb +61 -0
- data/lib/istat/utils.rb +35 -0
- data/lib/istat/version.rb +22 -0
- data/lib/istat.rb +9 -0
- data/spec/client_spec.rb +50 -0
- data/spec/frames/authentication_spec.rb +23 -0
- data/spec/frames/connection_test_spec.rb +18 -0
- data/spec/frames/measurement_request_spec.rb +117 -0
- data/spec/frames/register_spec.rb +22 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/utils_spec.rb +9 -0
- data/test_rc.sh +3 -0
- metadata +122 -0
@@ -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> »
|
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
|
data/lib/istat/client.rb
ADDED
@@ -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
|