#!/usr/bin/env perl
IO::Socket::SSL::set_ctx_defaults( SSL_verify_mode => SSL_VERIFY_NONE );
package INF::ILO;
use HTTP::Daemon::SSL;
use HTTP::Server::Brick;
use HTTP::Status;
use IO::Socket::SSL qw();
use HTML::TreeBuilder;
use HTTP::Request::Common;
use LWP::UserAgent;
use URI::Escape;
use File::Temp qw/ tempfile tempdir /;
use XML::Simple;
use Data::Dumper;
use JSON::PP;
sub read_file($) {
my ($name) = @_;
my $fh = new IO::File "<" . $name;
local $/;
my $guts = $fh->getline;
$fh->close;
undef $fh;
return $guts;
}
sub setup_port_proxy($$$) {
my ( $local_port, $remote_host, $remote_port ) = @_;
my $child = fork();
print STDERR "balance ",
join(
' ',
(
"balance", "-d", "-f", "127.0.0.1", $local_port,
$remote_host . ":" . $remote_port
)
),
"\n";
if ( $child == 0 ) {
exec( "balance", "-d", "-f", "-b", "127.0.0.1", $local_port,
$remote_host . ":" . $remote_port );
print STDERR "failed to start port proxy";
sleep(10000);
}
print "Setup proxy $local_port -> $remote_host:$remote_port\n";
return $child;
}
sub proxy($$$) {
my ( $self, $req, $res ) = @_;
if ( $req->uri->as_string =~ /^\/html\/java_irc.html/ ) {
$res->header( 'Content-type' => 'text/html' );
$res->add_content( $self->{java_html} );
$res->code(200);
return;
}
if ( $req->uri->as_string =~ /^\/html\/intgapp_.*\.jar/ ) {
$res->header( 'Content-type' => 'application/x-ms-application' );
$res->add_content(
read_file('/usr/local/share/inf/ilo/intgapp_221.jar') );
$res->code(200);
return;
}
my $proxy_req =
HTTP::Request->new( $req->method, $self->{ilo_url} . $req->uri->as_string,
[], $req->content );
$proxy_req->header( 'cookie' => 'sessionKey=' . $self->{skey} );
my $proxy_res = $self->{ua}->request($proxy_req);
unless ( $proxy_res->is_success ) {
print STDERR "request failed - did not get 200\n";
}
print "URI:", $req->uri->as_string, " code ", $proxy_res->code, " type ",
$proxy_res->header('Content-type'), "\n";
$res->code( $proxy_res->code );
$res->header( 'Content-type' => $proxy_res->header('Content-type') );
my $content = $proxy_res->content;
if ( $req->uri->as_string =~ /^\/json\/rc_info/ ) {
my $local_port = int( rand(30000) ) + 30000;
$content =~ s/"rc_port":(\d+),/"rc_port":$local_port,/;
push @{ $self->{to_kill} },
setup_port_proxy( $local_port, $self->{host}, $1 );
$local_port = int( rand(30000) ) + 30000;
$content =~ s/"vm_port":(\d+),/"vm_port":$local_port,/;
push @{ $self->{to_kill} },
setup_port_proxy( $local_port, $self->{host}, $1 );
}
$res->add_content($content);
}
sub login($) {
my $self = shift;
my $post = POST( $self->{ilo_url} . '/json/login_session' );
my $json =
'{"method":"login","user_login":"'
. $self->{user}
. '","password":"'
. $self->{password} . '"}';
$post->header( 'Content-Type' => 'application/json' );
$post->header( 'Content-Length' => length($json) );
$post->content($json);
my $res = $self->{ua}->request($post);
unless ( $res->is_success ) {
print STDERR "Login failed - did not get 200\n";
print Dumper($res);
$self->{skey} = undef;
return -1;
}
my $json = decode_json( $res->content );
$self->{skey} = $json->{session_key};
# print "Session key ".$self->{skey}."\n";
return 0;
}
sub view($) {
my $self = shift;
$self->login() unless defined $self->{skey};
my $get = GET( $self->{ilo_url} . '/html/java_irc.html?lang=en' );
my $res = $self->{ua}->request($get);
unless ( $res->is_success ) {
print STDERR "IRC frequest failed - did not get 200\n";
return -1;
}
my $content = $res->content;
unless ( $content =~ /Netscape'\) {(.*)}[\s\n]*else if/s ) {
print STDERR "returned html doesn't look right\n";
return -1;
}
$content = $1;
#$content=~ s/document.writeln\("(.*)"\);$/\1/m;
$content =~ s/^\s*document.writeln\("(.*)"\);\s*$/\1/mg;
$content =~ s/\\//g;
$content =~ s/RCINFO1=.*$/RCINFO1="$self->{skey}"/m;
$content =~ s/RCINFO6=.*$/RCINFO6="17990"/m;
$content =~ s/RCINFOLANG=.*$/RCINFOLANG="en"/m;
$content =~ s%(archive=)(/.*)$%\1$self->{proxy_url}\2%m;
$content = "<html><head></head><body>" . $content . "</body></html>";
$self->{java_html} = $content;
my $webserver_pid = fork();
if ( $webserver_pid == 0 ) {
$SIG{INT} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; };
$SIG{TERM} = sub { kill 'KILL', ( @{ $self->{to_kill} } ); die; };
$self->{server}->start;
print STDERR "failed to web server";
sleep(100000);
}
push @{ $self->{to_kill} }, $webserver_pid;
$SIG{INT} = sub { kill 'INT', ( @{ $self->{to_kill} } ); die; };
$SIG{TERM} = sub { kill 'TERM', ( @{ $self->{to_kill} } ); die; };
system( "appletviewer",
"-J-Djava.security.manager",
"-J-Djava.security.policy=/usr/local/share/inf/ilo/mypolicy",
"-J-Djavax.net.ssl.trustStore=/usr/local/share/inf/ilo/server.jks",
$self->{proxy_url} . "/html/java_irc.html"
);
kill 'TERM', ( @{ $self->{to_kill} } );
}
sub get_host_power($) {
my ($self) = @_;
$self->login() unless defined $self->{skey};
my $get = GET( $self->{ilo_url} . '/json/host_power' );
$get->header( 'cookie' => 'sessionKey=' . $self->{skey} );
my $res = $self->{ua}->request($get);
unless ( $res->is_success ) {
print STDERR " get host power - did not get 200\n";
return undef;
}
my $state = decode_json $res->content;
return $state->{'hostpwr_state'};
}
sub set_host_power($$) {
my ( $self, $what ) = @_;
$self->login() unless defined $self->{skey};
my $post = POST( $self->{ilo_url} . '/json/host_power' );
my $json =
'{"method":"' . $what . '","session_key":"' . $self->{skey} . '"}';
$post->header( 'Content-Type' => 'application/json' );
$post->header( 'Content-Length' => length($json) );
$post->content($json);
$post->header( 'cookie' => 'sessionKey=' . $self->{skey} );
my $res = $self->{ua}->request($post);
unless ( $res->is_success ) {
print STDERR " $what - did not get 200\n";
return 0;
}
return 1;
}
sub cold_boot($) {
my $self = shift;
return $self->set_host_power('system_coldboot');
}
sub reset($) {
my $self = shift;
return $self->set_host_power('system_reset');
}
sub off($) {
my $self = shift;
if ( $self->get_host_power =~ /ON/i ) {
return $self->set_host_power('hold_power_button');
}
return 1;
}
sub on($) {
my $self = shift;
if ( $self->get_host_power =~ /OFF/i ) {
return $self->set_host_power('press_power_button');
}
return 1;
}
sub port_on($$) {
my $self = shift;
return $self->on();
}
sub port_off($$) {
my $self = shift;
return $self->off();
}
sub port_cycle($$) {
my $self = shift;
return $self->cold_boot();
}
sub port_state_get_no_cache($$) {
my $self = shift;
return $self->get_host_power();
}
sub port_state_get($$) {
my $self = shift;
return $self->get_host_power();
}
sub port_name_get($$) {
my $self = shift;
return $self->{name};
}
sub name_get($) {
my $self = shift;
return $self->{name};
}
sub pdu_load_get($) {
return "N/A";
}
sub psu_status($) {
return "N/A";
}
sub port_count($) {
return 1;
}
sub port_id_get_by_number($$) {
return "K0";
}
sub new ($;$) {
my ( $class, $parm ) = @_;
my $self;
$self->{ua} = my $ua = LWP::UserAgent->new;
$self->{host} = $parm->{host} || "127.0.0.1";
$self->{user} = $parm->{user} || "Administrator";
$self->{password} = $parm->{password} || "";
$self->{name} = $parm->{name} || $self->{host};
$self->{ilo_url} = $parm->{ilo_url}
|| 'https://' . $self->{host};
$self->{userid} = undef;
$self->{ua}->ssl_opts(
SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE,
verify_hostname => 0,
);
my
$local_port = int( rand(30000) ) + 30000;
$self->{proxy_url} = 'https://127.0.0.1:' . $local_port;
$self->{server} = HTTP::Server::Brick->new(
port => $local_port,
daemon_class => 'HTTP::Daemon::SSL',
daemon_args => [
LocalAddr => '127.0.0.1',
SSL_key_file => '/usr/local/share/inf/ilo/server.key',
SSL_cert_file => '/usr/local/share/inf/ilo/server.crt',
],
);
$self->{server}->mount(
'/' => {
handler => sub {
my ( $req, $res ) = @_;
$self->proxy( $req, $res );
1;
},
wildcard => 1,
}
);
$self->{skey} = undef;
$self->{to_kill} = [];
return bless $self, $class;
}
1;