#!/usr/bin/env perl IO::Socket::SSL::set_ctx_defaults( SSL_verify_mode => SSL_VERIFY_NONE ); package INF::SuperMicro; use HTTP::Status; use HTTP::Cookies; 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; my $prefix = "/usr/local/share/inf/supermicro/"; my $jars = [ $prefix . "iKVM__V1.69.25.0x0.jar" ]; sub login($) { my $self = shift; my $post = POST( $self->{bmc_url} . '/cgi/login.cgi' ); my $form_content = 'name=' . $self->{user} . '&' . 'pwd=' . $self->{password}; $post->header( 'Content-Type' => 'application/x-www-form-urlencoded' ); $post->header( 'Content-Length' => length($form_content) ); $post->content($form_content); my $res = $self->{ua}->request($post); unless ( $res->is_success ) { print STDERR "Login failed - did not get 200\n"; print Dumper($res); $self->{logged_in} = undef; return -1; } $self->{logged_in} = 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->{logged_in}; my $get = GET( $self->{bmc_url} . '/cgi/url_redirect.cgi?url_name=ikvm&url_type=jwsk' ); my $res = $self->{ua}->request($get); unless ( $res->is_success ) { print STDERR "JWSK frequest failed - did not get 200\n"; return -1; } my $xml = new XML::Simple; my $c = $res->content; $c =~ s/^[\s\n\r]+//s; my $data = $xml->XMLin($c); return undef unless defined $data->{'application-desc'}; my $args = $data->{'application-desc'}->{'argument'}; return undef unless defined $args; mkdir $ENV{HOME} . "/.supermicro_kvm"; chdir $ENV{HOME} . "/.supermicro_kvm"; my $cp = join( ':', @$jars ); if ( $self->{proxy_host} ) { system( "echo", "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.useSystemProxies=false", "-DsocksProxyVersion=4", "-DsocksProxySet=true", "-DsocksProxyHost=" . $self->{proxy_host}, "-DsocksProxyPort=" . $self->{proxy_port}, "-cp", $cp, "-Djava.library.path=" . $prefix, "tw.com.aten.ikvm.KVMMain", @$args ); system( "java", "-Djava.net.preferIPv4Stack=true", "-Djava.net.useSystemProxies=false", "-DsocksProxyVersion=4", "-DsocksProxySet=true", "-DsocksProxyHost=" . $self->{proxy_host}, "-DsocksProxyPort=" . $self->{proxy_port}, "-cp", $cp, "-Djava.library.path=" . $prefix, "tw.com.aten.ikvm.KVMMain", @$args ); } else { system( "java", "-cp", $cp, "-Djava.library.path=" . $prefix, "tw.com.aten.ikvm.KVMMain", @$args ); } } # # 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->{logged_in}; my $post = POST( $self->{bmc_url} . '/cgi/ipmi.cgi' ); my $form_content = 'op=POWER_INFO.XML&r=(0%2C0)'; $post->header( 'Content-Type' => 'application/x-www-form-urlencoded' ); $post->header( 'Content-Length' => length($form_content) ); $post->content($form_content); my $res = $self->{ua}->request($post); unless ( $res->is_success ) { print STDERR " get host power - did not get 200\n"; return undef; } my $xml = new XML::Simple; my $c = $res->content; $c =~ s/^[\s\n\r]+//s; my $data = $xml->XMLin($c); return undef unless defined $data->{'POWER_INFO'}; return undef unless defined $data->{'POWER_INFO'}->{'POWER'}; return undef unless defined $data->{'POWER_INFO'}->{'POWER'}->{'STATUS'}; return $data->{'POWER_INFO'}->{'POWER'}->{'STATUS'}; } sub set_host_power($$) { my ( $self, $what ) = @_; $self->login() unless defined $self->{logged_in}; my $post = POST( $self->{bmc_url} . '/cgi/ipmi.cgi' ); my $form_content = 'op=POWER_INFO.XML&r=(1%2C' . $what . ')'; $post->header( 'Content-Type' => 'application/x-www-form-urlencoded' ); $post->header( 'Content-Length' => length($form_content) ); $post->content($form_content); my $res = $self->{ua}->request($post); unless ( $res->is_success ) { print STDERR " get host power - did not get 200\n"; return 0; } my $xml = new XML::Simple; my $c = $res->content; $c =~ s/^[\s\n\r]+//s; my $data = $xml->XMLin($c); return 0 unless defined $data->{'POWER_INFO'}; return 0 unless defined $data->{'POWER_INFO'}->{'POWER'}; return 0 unless defined $data->{'POWER_INFO'}->{'POWER'}->{'STATUS'}; return 1; } sub reset($) { my $self = shift; return $self->set_host_power('0'); } sub port_off($) { my $self = shift; return $self->set_host_power('1'); } sub orderly_shutdown($) { my $self = shift; return $self->set_host_power('2'); } sub port_on($) { my $self = shift; return $self->set_host_power('3'); } sub port_cycle($) { my $self = shift; return $self->set_host_power('5'); } 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->{cookie_jar} = HTTP::Cookies->new(); $self->{ua}->cookie_jar( $self->{cookie_jar} ); $self->{host} = $parm->{host} || "127.0.0.1"; $self->{user} = $parm->{user} || "ADMIN"; $self->{password} = $parm->{password} || "ADMIN"; $self->{name} = $parm->{name} || $self->{host}; $self->{bmc_url} = $parm->{bmc_url} || 'https://' . $self->{host}; $self->{ua}->ssl_opts( SSL_verify_mode => IO::Socket::SSL::SSL_VERIFY_NONE, verify_hostname => 0, ); if ( defined $parm->{proxy_host} ) { $self->{ua}->proxy( [qw(http https)] => "socks://" . $parm->{proxy_host} . ":" . $parm->{proxy_port} ); $self->{proxy_host} = $parm->{proxy_host}; $self->{proxy_port} = $parm->{proxy_port}; } $self->{logged_in} = undef; return bless $self, $class; } 1;