Skip to content

Commit

Permalink
Major restructuring
Browse files Browse the repository at this point in the history
  • Loading branch information
sosedoff committed Nov 3, 2011
1 parent d4f0174 commit 3a677a1
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 122 deletions.
4 changes: 3 additions & 1 deletion lib/munin-ruby.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'munin-ruby/version' require 'munin-ruby/version'
require 'munin-ruby/stat' require 'munin-ruby/errors'
require 'munin-ruby/parser'
require 'munin-ruby/connection'
require 'munin-ruby/node' require 'munin-ruby/node'
72 changes: 72 additions & 0 deletions lib/munin-ruby/connection.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,72 @@
require 'socket'

module Munin
class Connection
include Munin::Parser

attr_reader :host, :port

# Initialize a new connection to munin-node server
#
# host - Server host (default: 127.0.0.1)
# port - Server port (default: 4949)
#
def initialize(host='127.0.0.1', port=4949)
@host = host
@port = port
@socket = nil
@connected = false
end

# Returns true if socket is connected
#
def connected?
@connected == true
end

# Establish connection to the server
#
def connect
begin
@socket = TCPSocket.new(@host, @port)
@socket.sync = true
welcome = @socket.gets
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET => ex
raise Munin::ConnectionError, ex.message
rescue EOFError
raise Munin::AccessDenied
end
end

# Close connection
#
def close
@socket.close unless @socket.nil?
end

# Send a string of data followed by a newline symbol
#
def send_data(str)
connect unless connected?
@socket.puts("#{str.strip}\n")
end

# Reads a single line from socket
#
def read_line
@socket.gets.strip
end

# Reads a packet of data until '.' reached
#
def read_packet
lines = []
while(str = @socket.readline) do
break if str.strip == '.'
lines << str.strip
end
parse_error(lines)
lines
end
end
end
8 changes: 8 additions & 0 deletions lib/munin-ruby/errors.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,8 @@
module Munin
class MuninError < StandardError ; end
class ConnectionError < MuninError ; end
class AccessDenied < MuninError ; end
class InvalidResponse < MuninError ; end
class UnknownService < MuninError ; end
class BadExit < MuninError ; end
end
123 changes: 33 additions & 90 deletions lib/munin-ruby/node.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,112 +1,55 @@
require 'socket'

module Munin module Munin
class SessionError < StandardError ; end
class NoSuchService < StandardError ; end
class AccessDenied < StandardError ; end

class Node class Node
attr_reader :host, :port include Munin::Parser
attr_reader :version, :services
attr_reader :timestamp


# Initialize a new Munin::Node object attr_reader :connection

# Initialize a new Node instance
# #
# host - Server hostname or IP address # host - Server host
# opts - Additional options. # port - Server port
# :port - Node server port (default to 4949)
# :fetch - String or Array of service names ONLY to fetch
# #
def initialize(host, opts={}) def initialize(host='127.0.0.1', port=4949)
@host = host @connection = Munin::Connection.new(host, port)
@port = opts[:port] || 4949
@stats = {}
@services = []
@version = ''
@only_services = opts[:fetch] || []

if @only_services.kind_of?(Array)
@only_services.uniq!
elsif @only_services.kind_of?(String)
@only_services = @only_services.scan(/[a-z\d\-\_]{1,}/i).uniq
else
@only_services = []
end

run
end end


# Returns a set of parameters for the service # Get a node version
#
# name - Service name
#
# @return [Munin::Stat]
# #
def service(name) def version
if has_service?(name) connection.send_data("version")
@stats[name] str = connection.read_line
if str =~ /^munins node on/
str.split.last
else else
raise Munin::NoSuchService, "Service with name #{name} does not exist." raise InvalidResponse
end end
end end


# Returns true if node has the service # Get a list of all available metrics
# #
# name - Service name def list
# connection.send_data("list")
def has_service?(name) connection.read_line.split
@stats.key?(name)
end end


# Fetch multiple services at once # Get a configuration information for service
# #
# service_names - Array of service names to fetch # service - Name of the service
# #
def snapshot(service_names=[]) def config(service)
service_names.uniq.map { |n| service(n) } connection.send_data("config #{service}")
lines = connection.read_packet
parse_config(lines)
end end


private # Get all service metrics values

#
# Fetch node information and stats # service - Name of the service
def run #
begin
@timestamp = Time.now
@socket = TCPSocket.new(@host, @port)
@socket.sync = true ; @socket.gets
fetch_version
fetch_services
@socket.close
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::ECONNRESET => ex
raise Munin::SessionError, ex.message
rescue EOFError
raise Munin::AccessDenied
end
end

# Fetch node server version
def fetch_version
@socket.puts("version")
@version = @socket.readline.strip.split(' ').last
end

# Fetch list of services and its stats
def fetch_services
@socket.puts("list")
services = @socket.readline.split(' ').map { |s| s.strip }.sort
services = services.select { |s| @only_services.include?(s) } unless @only_services.empty?
services.each { |s| @services << s ; @stats[s] = fetch(s) }
end

# Fetch service information
def fetch(service) def fetch(service)
@socket.puts("fetch #{service}") connection.send_data("fetch #{service}")
content = [] lines = connection.read_packet
while(str = @socket.readline) do parse_fetch(lines)
break if str.strip == '.'
content << str.strip.split(' ')
end
Stat.new(service, content)
end end
end end
end end
57 changes: 57 additions & 0 deletions lib/munin-ruby/parser.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,57 @@
module Munin
module Parser
private

# Parse 'config' request
#
def parse_config(data)
config = {:graph => {}, :metrics => {}}
data.each do |l|
if l =~ /^graph_/
key_name, value = l.scan(/^graph_([\w]+)\s(.*)/).flatten
config[:graph][key_name] = value
elsif l =~ /^[a-z]+\./
matches = l.scan(/^([a-z\d\-\_]+)\.([a-z\d\-\_]+)\s(.*)/).flatten
config[:metrics][matches[0]] ||= {}
config[:metrics][matches[0]][matches[1]] = matches[2]
end
end

# Now, lets process the args hash
if config[:graph].key?('args')
args = {}
config[:graph]['args'].scan(/--([a-z\-\_]+)\s([\d]+)\s?/).each do |arg|
args[arg.first] = arg.last
end
config[:graph]['args'] = args
end

config
end

# Parse 'fetch' request
#
def parse_fetch(data)
process_data(data)
end

def process_data(lines)
data = {}
lines.each do |line|
line = line.split
key = line.first.split('.value').first
data[key] = line.last
end
data
end

def parse_error(lines)
if lines.size == 1
case lines.first
when '# Unknown service' then raise UnknownService
when '# Bad exit' then raise BadExit
end
end
end
end
end
30 changes: 0 additions & 30 deletions lib/munin-ruby/stat.rb

This file was deleted.

2 changes: 1 addition & 1 deletion lib/munin-ruby/version.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,5 +1,5 @@
module Munin module Munin
unless defined?(::Munin::VERSION) unless defined?(::Munin::VERSION)
VERSION = '0.1.0' VERSION = '0.2.0'
end end
end end

0 comments on commit 3a677a1

Please sign in to comment.