Created
March 1, 2011 17:02
-
-
Save oogali/849458 to your computer and use it in GitHub Desktop.
Connect to Manaviz KVM without opening a browser (tested on OS X)
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
#!/usr/bin/env ruby | |
# | |
# I hate ManaWiz KVMs. That is all. | |
# | |
# Create a file in your home directory called ".kvmcfg" with the following: | |
# :kvm_user: yourusername | |
# :kvm_passwd: yourpassword | |
# | |
# Then run this marvelous script: | |
# $ ./kvm.rb servername-oob.whatever.com | |
# | |
# - @oogali | |
# | |
# | |
require 'rubygems' | |
require 'thread' | |
require 'net/ssh' | |
require 'curb' | |
require 'yaml' | |
require 'nokogiri' | |
require 'socket' | |
include Socket::Constants | |
class CurbWrapper | |
attr_reader :base | |
attr_reader :curb | |
attr_reader :channel_number | |
attr_reader :session_id | |
def initialize(base_url = nil, verbose = false) | |
@base = base_url | |
raise "No URL specified" unless @base | |
@curb = Curl::Easy.new | |
@curb.enable_cookies = true | |
@curb.cookies = 'SessionCookie=LOGGED_OUT' | |
@curb.verbose = verbose | |
@curb.url = @base | |
reset false | |
end | |
def cookies | |
@curb.cookies | |
end | |
def cookies=(jar) | |
@curb.cookies = jar | |
end | |
def channel_number=(chan) | |
@channel_number = chan | |
@curb.cookies += "ChannelNumber=#{chan};" | |
end | |
def session_id=(sid) | |
@session_id = sid | |
@curb.cookies = "SessionCookie=#{sid};" | |
end | |
def url(path = nil) | |
@curb.url = File.join @base, path if path | |
@curb.url | |
end | |
def get(path) | |
url path | |
begin | |
@curb.perform | |
rescue Curl::Err::PartialFileError | |
end | |
body | |
end | |
def post(path, params) | |
url path | |
@curb.http_post params.map { |k,v| "#{k}=#{v}" }.join('&') | |
@curb.perform | |
body | |
end | |
def body | |
@curb.body_str | |
end | |
def headers | |
@curb.headers | |
end | |
def reset(hard_reset = true) | |
if hard_reset | |
old_url = @curb.url | |
@curb.reset | |
@curb.url = old_url | |
end | |
headers['User-Agent'] = 'Mozilla/5.0' | |
@curb.cookies = "SessionCookie=#{@session_id}; " if @session_id | |
@curb.cookies += "ChannelNumber=#{@channel_number}; " if @channel_number | |
@curb.version = Curl::HTTP_1_1 | |
@curb.use_ssl = Curl::CURL_USESSL_ALL | |
@curb.ssl_verify_host = false | |
@curb.ssl_verify_peer = false | |
end | |
end | |
# install sigint signal handler | |
interrupted = false | |
trap('INT') { interrupted = true } | |
# print usage if we get incorrect amount of args | |
if ARGV.length <= 0 | |
$stderr.puts "#{$0} <kvm ip>" | |
exit | |
end | |
# grab kvm host from argv stack | |
kvm_host = ARGV.shift | |
# set our default options | |
config = Hash.new | |
config[:gw_user] = ENV['USER'] | |
config[:gw_host] = nil | |
config[:kvm_user] = 'admin' | |
config[:kvm_passwd] = nil | |
config[:forward_port] = 8443 | |
config[:jv_port] = 7578 | |
# merge config file with our options | |
config.update YAML.load_file(ENV['HOME'] + '/.kvmcfg') | |
Thread.abort_on_exception = true | |
started = 0 | |
new_forwards = Array.new | |
# set destination web host and port | |
web_host = config[:gw_host] ? 'localhost' : kvm_host | |
web_port = config[:gw_host] ? config[:forward_port] : 443 | |
# if we're given a gateway host, then we should connect to it first | |
if config[:gw_host] | |
# spin up new ssh thread, and forward port | |
ssh_thread = Thread.new do | |
Thread.current[:connected] = false | |
Net::SSH.start(config[:gw_host], config[:gw_user]) do |session| | |
session.forward.local(web_port, kvm_host, 443) | |
session.forward.local(config[:jv_port], kvm_host, 7578) | |
Thread.current[:connected] = true | |
session.loop { true } | |
end | |
end | |
# check every 125ms if we're connected | |
until ssh_thread[:connected] do | |
sleep 0.125 | |
end | |
end | |
# wait 500ms for thread to settle. why? i dunno, but it works for now. | |
sleep 0.5 | |
# initialize our wrapper and ping manaviz to make sure we're alive | |
c = CurbWrapper.new "https://#{web_host}:#{web_port}", true | |
c.get '/login.asp' | |
c.get '/page/login.html' | |
# validate session | |
c.get '/rpc/WEBSES/validate.asp' | |
c.reset | |
# create an authenticated session | |
session = c.post '/rpc/WEBSES/create.asp', { :WEBVAR_USERNAME => config[:kvm_user], :WEBVAR_PASSWORD => config[:kvm_passwd] } | |
c.session_id = session.match(/'SESSION_COOKIE'\s+:\s+'(\S+)'\s*,/)[1] | |
c.channel_number = session.match(/'CHANNEL_NUMBER'\s+:\s+(\d+)/)[1] | |
c.reset | |
# download jviewer jar if we don't have it on disk | |
# | |
# why am i caching? | |
# * because this stupid kvm goes unresponsive from time to time on a large download like say, the jar file you need for kvm | |
# ** leading to you being locked out of your kvm for minutes, hours, or days; or until you yank power from the server | |
# ** do you know how frustrating it is to not be able to access your server's kvm when you need to? | |
# **** yes, i am really fucking angry. | |
# ***** yes, i really do mean YANK power from the server. as long as the server has power, manawiz remains hung and useless. | |
# ****** no, i will not do 1-3 RMAs/week of motherboards in my datacenter footprint. | |
# ******* have you ever RMA'd a motherboard? i'd much rather buy dedicated kvm hardware. and stop buying motherboards featuring 'onboard kvm' from flextronics/supermicro/etc. | |
if not File.exists? '/tmp/JViewer.jar' | |
jar = File.open '/tmp/JViewer.jar', 'w+' | |
jar.write c.get '/Java/release/JViewer.jar' | |
jar.close | |
end | |
# send http request for jnlp | |
jnlp = c.get '/Java/jviewer.jnlp' | |
p jnlp | |
# parse jnlp for jviewer args | |
doc = Nokogiri::XML jnlp | |
args = doc.xpath('//jnlp/application-desc/argument') | |
# assign args to var, use curl ip for host to deal with forwarding magic | |
jviewer_host = c.curb.primary_ip | |
jviewer_remote_port = args[1].text.to_i | |
jviewer_auth = args[2].text | |
# if we're forwarding connections, then replace hosts in jnlp file | |
if kvm_host != jviewer_host | |
jnlp.sub! "https://#{kvm_host}", "https://#{web_host}:#{web_port}" | |
jnlp.sub! kvm_host, jviewer_host | |
end | |
# write jnlp to temp file | |
j = File.new("/tmp/kvm.#{$$}.jnlp", "w+") | |
j.write(jnlp) | |
j.close | |
# sleep 500ms and then launch jnlp | |
sleep 0.5 | |
system('java', "-Xdock:name=Manawiz KVM", '-jar', '/tmp/JViewer.jar', jviewer_host, jviewer_remote_port.to_s, jviewer_auth + "\002") | |
# hold session open for 30 minutes, or until we get a ctrl+c | |
ts = Time.now.to_i | |
while Time.now.to_i < ts + 1800 | |
break if interrupted | |
sleep 0.125 | |
end | |
p c.get '/rpc/WEBSES/logout.asp' | |
# kill ssh thread | |
ssh_thread.kill if ssh_thread |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment