#!/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 = "" . $content . ""; $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 logout($) { my $self = shift; } 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;