From c2f0aa2136be314b928ea9cc4c4c86e6c21b4b1a Mon Sep 17 00:00:00 2001 From: Aaron Alexander Date: Tue, 27 Jan 2015 18:22:55 -0500 Subject: [PATCH 1/4] Update to the M/monit 3.4 API --- README.md | 53 +++++++++++++++++----------- lib/mmonit/connection.rb | 76 +++++++++++++++++++++++----------------- 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index bd8b9ab..9895162 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,48 @@ -mmonit-ruby -=========== +# mmonit-ruby Ruby interface for M/Monit -All the commands listed here are currently available: +A subset of the [M/Monit HTTP API](http://mmonit.com/documentation/http-api/) commands are currently available. Requests are currently read-only. -http://mmonit.com/wiki/MMonit/HTTP-API +## Available Commands -Requests are read-only until I find a way to do more. +* `connect` - Connect to M/Monit and establish a session +* `status` - Status overview +* `status_detailed(id_or_fqdn)` - Detailed status for a specified host + * `id_or_fqdn` - Either the numeric id or the fully-qualified domain name for a host +* `events` - Events overview +* `event(id)` - Detailed information about an event + * `id` - The numeric id for an event +* `hosts` - A list of hosts +* `host(id_or_fqdn)` - Detailed information about a specified host + * `id_or_fqdn` - Either the numeric id or the fully-qualified domain name for a host +* `users` - A list of users +* `user(id)` - Detailed information about a user + * `id` - The numeric id for a user +* `groups` - A list of groups +## Usage + require 'mmonit-ruby' + mmonit = MMonit::Connection.new({ + :ssl => true, + :username => 'USERNAME', + :password => 'PASSWORD', + :address => 'example.com', + :port => '443' + }) -mmonit = MMonit::Connection.new({ - :ssl => true, - :username => 'USERNAME', - :password => 'PASSWORD', - :address => 'example.com', - :port => '443' -}) - -mmonit.connect - -hosts = mmonit.hosts - -p hosts + mmonit.connect + hosts = mmonit.hosts +## Custom Requests Custom requests can be made like: -mmonit.request(path, [body]) + require 'mmonit-ruby' + + mmonit.request(path, [body]) -body is optional \ No newline at end of file +`body` is optional \ No newline at end of file diff --git a/lib/mmonit/connection.rb b/lib/mmonit/connection.rb index bb7dc09..33fb527 100644 --- a/lib/mmonit/connection.rb +++ b/lib/mmonit/connection.rb @@ -21,7 +21,7 @@ def initialize(options = {}) 'Referer' => "#{@url}/index.csp", 'Content-Type' => 'application/x-www-form-urlencoded', 'User-Agent' => @useragent, - 'Connection' => 'keepalive' + 'Connection' => 'Keep-Alive' } end @@ -38,59 +38,71 @@ def connect end def login - self.request('/z_security_check', "z_username=#{@username}&z_password=#{@password}").code.to_i == 302 + self.request('/z_security_check', "z_username=#{@username}&z_password=#{@password}", true).code.to_i == 302 end + # Status API: http://mmonit.com/documentation/http-api/Methods/Status def status - JSON.parse(self.request('/json/status/list').body)['records'] + JSON.parse(self.request('/status/hosts/list').body)['records'] end - def hosts - JSON.parse(self.request('/json/admin/hosts/list').body)['records'] + def status_detailed(id_or_fqdn) + host = find_host(id_or_fqdn) + host.nil? ? nil : JSON.parse(self.request("/status/hosts/get?id=#{host['id']}").body)['records']['host'] rescue nil end - def users - JSON.parse(self.request('/json/admin/users/list').body) + # Events API: http://mmonit.com/documentation/http-api/Methods/Events + def events + JSON.parse(self.request('/reports/events/list').body)['records'] end - def alerts - JSON.parse(self.request('/json/admin/alerts/list').body) + def event(id) + JSON.parse(self.request("/reports/events/get?id=#{id}").body) rescue nil end - def events - JSON.parse(self.request('/json/events/list').body)['records'] + # Admin Hosts API: http://mmonit.com/documentation/http-api/Methods/Admin_Hosts + def hosts + JSON.parse(self.request('/admin/hosts/list').body)['records'] end - #### topography and reports are disabled until I figure out their new equivalent in M/Monit - # def topography - # JSON.parse(self.request('/json/status/topography').body) - # end + def host(id_or_fqdn) + host = find_host(id_or_fqdn) + host.nil? ? nil : JSON.parse(self.request("/admin/hosts/get?id=#{host['id']}").body) rescue nil + end - # def reports(hostid=nil) - # body = String.new - # body = "hostid=#{hostid.to_s}" if hostid - # JSON.parse(self.request('/json/reports/overview', body).body) - # end + # Admin Users API: http://mmonit.com/documentation/http-api/Methods/Admin_Users + def users + JSON.parse(self.request('/admin/users/list').body) + end - def find_host(fqdn) - host = self.hosts.select{ |h| h['host'] == fqdn } - host.empty? ? nil : host.first + def user(username) + JSON.parse(self.request("/admin/users/get?uname=#{username}").body) rescue nil end - # another option: /admin/hosts/json/get?id=#### - def get_host_details(id) - JSON.parse(self.request("/json/status/detail?hostid=#{id}").body)['records']['host'] rescue nil + # Admin Groups API: http://mmonit.com/documentation/http-api/Methods/Admin_Groups + def groups + JSON.parse(self.request('/admin/groups/list').body) end - def delete_host(host) - host = self.find_host(host['host']) if host.key?('host') && ! host.key?('id') - return false unless host['id'] - self.request("/admin/hosts/delete?id=#{host['id']}") + # Helpers + def find_host(id_or_fqdn) + hosts = self.hosts rescue [] + host = hosts.select{ |h| h['id'] == id_or_fqdn || h['host'] == id_or_fqdn } + host.empty? ? nil : host.first end - def request(path, body="", headers = {}) + def request(path, body="", is_post = false, headers = {}) self.connect unless @http.is_a?(Net::HTTP) - @http.post(path, body, @headers.merge(headers)) + if is_post + @http.post(path, body, @headers.merge(headers)) + else + @http.get(path, @headers.merge(headers)) + end + end + + # Backwards compatability + def get_host_details(id) # Left for backwards compatability + status_detailed(id) end end end \ No newline at end of file From cc2dc89f2a16ef7b50118633d89aac29d50e0736 Mon Sep 17 00:00:00 2001 From: Aaron Alexander Date: Wed, 28 Jan 2015 09:31:05 -0500 Subject: [PATCH 2/4] Lookup the host from the status API for detailed status (to handle logins that don't have administrator access) --- lib/mmonit/connection.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/mmonit/connection.rb b/lib/mmonit/connection.rb index 33fb527..15f85a8 100644 --- a/lib/mmonit/connection.rb +++ b/lib/mmonit/connection.rb @@ -47,8 +47,8 @@ def status end def status_detailed(id_or_fqdn) - host = find_host(id_or_fqdn) - host.nil? ? nil : JSON.parse(self.request("/status/hosts/get?id=#{host['id']}").body)['records']['host'] rescue nil + status = find_status(id_or_fqdn) + status.nil? ? nil : JSON.parse(self.request("/status/hosts/get?id=#{status['id']}").body)['records']['host'] rescue nil end # Events API: http://mmonit.com/documentation/http-api/Methods/Events @@ -91,6 +91,12 @@ def find_host(id_or_fqdn) host.empty? ? nil : host.first end + def find_status(id_or_fqdn) + statuses = self.status rescue [] + status = statuses.select{ |s| s['id'] == id_or_fqdn || s['hostname'] == id_or_fqdn } + status.empty? ? nil : status.first + end + def request(path, body="", is_post = false, headers = {}) self.connect unless @http.is_a?(Net::HTTP) if is_post From ca27642ff5dcb8e6b14b068d97f0b3a25b9fff06 Mon Sep 17 00:00:00 2001 From: Aaron Alexander Date: Wed, 28 Jan 2015 09:53:04 -0500 Subject: [PATCH 3/4] Change 'host' to 'hostname' for the host lookup --- lib/mmonit/connection.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mmonit/connection.rb b/lib/mmonit/connection.rb index 15f85a8..759e8c1 100644 --- a/lib/mmonit/connection.rb +++ b/lib/mmonit/connection.rb @@ -87,7 +87,7 @@ def groups # Helpers def find_host(id_or_fqdn) hosts = self.hosts rescue [] - host = hosts.select{ |h| h['id'] == id_or_fqdn || h['host'] == id_or_fqdn } + host = hosts.select{ |h| h['id'] == id_or_fqdn || h['hostname'] == id_or_fqdn } host.empty? ? nil : host.first end From d556f695e9e4c0dfa4f08e63996ca9f3c8a18f56 Mon Sep 17 00:00:00 2001 From: Aaron Alexander Date: Tue, 10 Feb 2015 09:59:59 -0500 Subject: [PATCH 4/4] Only do the id lookup if the id_or_fqdn parameter is not already an Integer --- lib/mmonit/connection.rb | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/mmonit/connection.rb b/lib/mmonit/connection.rb index 759e8c1..901c959 100644 --- a/lib/mmonit/connection.rb +++ b/lib/mmonit/connection.rb @@ -47,8 +47,8 @@ def status end def status_detailed(id_or_fqdn) - status = find_status(id_or_fqdn) - status.nil? ? nil : JSON.parse(self.request("/status/hosts/get?id=#{status['id']}").body)['records']['host'] rescue nil + id = find_status_id(id_or_fqdn) + id.nil? ? nil : JSON.parse(self.request("/status/hosts/get?id=#{id}").body)['records']['host'] rescue nil end # Events API: http://mmonit.com/documentation/http-api/Methods/Events @@ -66,8 +66,8 @@ def hosts end def host(id_or_fqdn) - host = find_host(id_or_fqdn) - host.nil? ? nil : JSON.parse(self.request("/admin/hosts/get?id=#{host['id']}").body) rescue nil + id = find_host_id(id_or_fqdn) + id.nil? ? nil : JSON.parse(self.request("/admin/hosts/get?id=#{id}").body) rescue nil end # Admin Users API: http://mmonit.com/documentation/http-api/Methods/Admin_Users @@ -91,12 +91,26 @@ def find_host(id_or_fqdn) host.empty? ? nil : host.first end + def find_host_id(id_or_fqdn) + return id_or_fqdn if id_or_fqdn.is_a?(Integer) + + data = find_status(id_or_fqdn) + data.nil? ? nil : data['id'] + end + def find_status(id_or_fqdn) statuses = self.status rescue [] status = statuses.select{ |s| s['id'] == id_or_fqdn || s['hostname'] == id_or_fqdn } status.empty? ? nil : status.first end + def find_status_id(id_or_fqdn) + return id_or_fqdn if id_or_fqdn.is_a?(Integer) + + data = find_status(id_or_fqdn) + data.nil? ? nil : data['id'] + end + def request(path, body="", is_post = false, headers = {}) self.connect unless @http.is_a?(Net::HTTP) if is_post