Commit 459bff13 authored by Andrew Newdigate's avatar Andrew Newdigate
Browse files

Merge branch 'ruby-hostinfo' into 'master'

Ruby hostinfo

Closes #734

See merge request gitlab-com/migration!158
parents 2a9f69df 3c496512
...@@ -3,76 +3,5 @@ ...@@ -3,76 +3,5 @@
set -euo pipefail set -euo pipefail
IFS=$'\n\t' IFS=$'\n\t'
function network_owner() {
local ip=$(dig ${1} +short|tail -1)
if [[ -z $ip ]]; then
echo "DOES_NOT_RESOLVE"
else
local who_is=$(whois ${ip}|grep OrgName|sed -E 's/^.*: +//')
if [[ -z $who_is ]]; then
echo "N/A"
else
echo "$who_is"
fi
fi
}
function rev_name() {
local ip=$(dig ${1} +short|tail -1)
if [[ -z $ip ]]; then
echo "DOES_NOT_RESOLVE"
else
local rev_ip=$(dig -x ${ip} +short)
if [[ -z $rev_ip ]]; then
echo $ip
else
echo $rev_ip
fi
fi
}
function ssh_port_open() {
result=$(ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -oConnectTimeout=5 -p "$2" "git@$1" 2>/dev/null)
if [[ "$result" =~ "Welcome to GitLab" ]]; then
echo Yes
else
echo No
fi
}
function ssh_port() {
if [[ $1 == altssh* ]]; then
echo 443
else
echo 22
fi
}
function http_status() {
local status=$((curl --insecure --head --connect-timeout 5 --max-time 5 --silent ${1}|head -1|cut -d\ -f2) || echo "Error")
if [[ -z $status ]]; then
echo "Invalid"
else
echo "$status"
fi
}
function redirect() {
if ! curl --insecure --head --connect-timeout 5 --max-time 5 --silent "$1"|grep Location|sed -E 's/^.*: +//'|cut -c 1-40; then
echo "-"
fi
}
function run() {
printf '%s\t%s\t%s\t%s\t%s\t%s\t\t%s\n' "HOST" "NETWORK" "REV" "HTTPS" "SSH" "REDIRECT"
for host in "$@"
do
printf "%s\t%s\t%s\t%s\t%s\t%s\n" "$host" $(network_owner $host) $(rev_name $host) $(http_status "https://$host") $(ssh_port_open $host $(ssh_port $host)) $(redirect "https://$host")
done
}
echo -e "Date: $(date '+%F %T')\n" echo -e "Date: $(date '+%F %T')\n"
run $@ | column -t -s $'\t' ruby "$(dirname $0)/hostinfo.rb" "$@" | column -t -s $'\t'
#!/usr/bin/env ruby
Thread.abort_on_exception = true
require 'net/https'
class Check
# These are provided or computed
attr_reader :hostname, :https_url, :ssh_port
# These are looked up in parallel
attr_reader :ip, :https_response, :ssh_port_open, :network_owner, :rev_name
def initialize(hostname)
@hostname = hostname
@https_url = "https://#{hostname}"
@ssh_port = hostname.start_with?('altssh') ? 443 : 22
end
def execute
parallel_lookup!
[
hostname,
network_owner,
rev_name,
https_status,
ssh_port_open,
redirect
].join("\t")
end
def https_status
return "Invalid" unless https_response
https_response.code
end
def redirect
return "-" unless https_response && https_response.key?('Location')
https_response['Location'][0..39]
end
private
def parallel_lookup!
# Checking whois and reverse IP lookup depends on the IP being resolved,
# so set it off separately
ip_thread = Thread.new { @ip = resolv(hostname) }
threads = [
Thread.new { @https_response = curl(https_url) },
Thread.new { @ssh_port_open = check_ssh }
]
# Once this join completes, it's safe to reference the IP
ip_thread.join
threads.concat([
Thread.new { @network_owner = check_network_owner },
Thread.new { @rev_name = check_rev_name }
])
threads.map(&:join)
end
def popen(cmd)
cmd.push(err: :close)
result = IO.popen(cmd) { |io| io.read.strip }
if $?.success?
result
else
nil
end
end
def check_ssh
result = popen(%W[
ssh -o UserKnownHostsFile=/dev/null \
-o StrictHostKeyChecking=no \
-oConnectTimeout=5 \
-p #{ssh_port} \
-q -T \
git@#{hostname}
])
if result =~ /Welcome to GitLab/
"Yes"
else
"No"
end
end
def check_network_owner
return "DOES_NOT_RESOLVE" unless ip
whois(ip) || "N/A"
end
def check_rev_name
return "DOES_NOT_RESOLVE" unless ip
resolv(ip, ptr: true) || ip
end
def resolv(hostname, ptr: false)
cmd = ['dig', '+short']
cmd << '-x' if ptr
cmd << hostname
result = popen(cmd)
return nil unless result
result.split("\n")[-1]
end
def whois(thing)
result = popen(%W[whois #{thing}])
return nil unless result
orgname = result.lines.find { |l| l =~ /OrgName:/ }
orgname&.split(":", 2)[1].strip
end
def curl(url)
result = popen(%W[curl --insecure --head --connect-timeout 5 --max-time 5 --silent #{url}])
return nil unless result
lines = result.lines.map(&:chomp)
return nil unless lines.size > 1
version, code, message = lines[0].split(" ")
kls = Net::HTTPResponse::CODE_TO_OBJ[code] || Net::HTTPResponse
out = kls.new(version, code, message)
lines[1..-1].map do |line|
key, value = line.split(": ")
out.add_field(key, value)
end
out
end
end
class Checks
class << self
def header
["HOST", "NETWORK", "REV", "HTTPS", "SSH", "REDIRECT"].join("\t")
end
end
attr_reader :checks
def initialize(hostnames)
@checks = hostnames.map { |hostname| Check.new(hostname) }
end
def execute
threads = checks.map { |check| Thread.new { check.execute } }
threads.map(&:value)
end
end
results = Checks.new(ARGV).execute
STDOUT.puts Checks.header
results.each { |result| STDOUT.puts result }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment