Created
November 26, 2015 09:01
-
-
Save patio11/d26e42fbd55d39426c40 to your computer and use it in GitHub Desktop.
Implementing a /healthcheck endpoint in Slack to read out consul status in a human-readable fashion
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SlackController < ApplicationController | |
skip_before_action :verify_authenticity_token | |
@@slack_security_tokens = | |
["copy-paste-the-token-you-get-from-Slack-when-configuring-the-integration-here"] | |
before_filter :bounce_access_not_from_slack | |
def healthcheck | |
services = SystemStatus.list_services | |
if services.blank? | |
render json: { | |
response_type: "in_channel", | |
text: "PlayerUI couldn't connect successfully to consul cluster. BAD NEWS." | |
} | |
else | |
arguments = params[:text] | |
node_filter = nil | |
if arguments.present? && services.include?(arguments.split(" ")[0]) | |
# /healthcheck gm <-- Filters results down to only gm nodes | |
services = [arguments.split(" ")[0].strip] | |
elsif arguments.present? && (arguments.split(" ")[0].present?) | |
# /healthcheck 172.31.16.60 <-- Filters results down to only this IP. | |
node_filter = arguments.split(" ")[0].strip | |
end | |
response = [] | |
services.each do |service| | |
status = SystemStatus.service_up?(service) | |
status_string = status ? "[UP]" : "[*DOWN*]" | |
nodes = SystemStatus.list_service_nodes(service) | |
node_details = [] | |
nodes.each do |node| | |
tags = (node[:tags].length < 10) ? node[:tags].join("|") : (node[:tags][0..9].join("|") + "...") | |
detail = "#{node[:address]}:#{node[:port]} (#{tags})" | |
detail = "~#{detail}~" unless SystemStatus.service_up?(service, node[:tags].first) | |
node_details << detail if node_filter.blank? || (node_filter == node[:address]) | |
end | |
response << [service, status_string, node_details].join(" ") if node_filter.blank? || node_details.present? | |
end | |
render json: { | |
response_type: "in_channel", | |
text: response.join("\n") | |
} | |
end | |
private | |
def bounce_access_not_from_slack | |
unless Rails.env.development? || @@slack_security_tokens.include?(params[:token]) | |
raise "Not authorized: token sent doesn't match pre-configured Slack security token." | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'resolv' | |
class SystemStatus | |
def self.list_services | |
services = JSON.parse(RestClient.get("http://localhost:8500/v1/catalog/services")) rescue nil | |
services ? services.keys : nil | |
end | |
def self.list_service_nodes(service) | |
nodes = JSON.parse(RestClient.get("http://localhost:8500/v1/catalog/service/#{service}")) rescue [] | |
nodes.map do |node| | |
node[:address] = node["ServiceAddress"].present? ? node["ServiceAddress"] : node["Address"] | |
node[:port] = node["ServicePort"] || (node["Port"] || "0").to_i | |
node[:tags] = node["ServiceTags"] || [] | |
node[:node] = node["Node"] | |
end | |
nodes | |
end | |
def self.service_up?(service, tag = nil) | |
if !tag | |
(!!dns.getaddress("#{service}.service.consul")) rescue false | |
else | |
(!!dns.getaddress("#{tag}.#{service}.service.consul")) rescue false | |
end | |
end | |
def self.node_up?(node) | |
(!!dns.getaddress("#{node}.node.consul")) rescue false | |
end | |
def self.service_statuses(bust_cache = false) | |
t = bust_cache ? nil : Time.now.to_i | |
Rails.cache.fetch("SystemStatus.service_statuses(#{t})", :expires_in => 1.minute) do | |
services = list_services | |
services.inject({}) {|acc, service| acc[service] = service_up?(service) ? "up" : "down"; acc} | |
end | |
end | |
def self.dns | |
Resolv::DNS.new(nameserver: ["127.0.0.1"]) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
MIT license, same as Rails. Feel free to hack the heck out of this. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Needs more emoticons ✅ and ❌