<h3>Administration Panel</h3>
<& SELF:err &>
% if ($need_confirm) {
<& SELF:confirm &> 
% } else { 
<& SELF:dev_control &>
% }
<h4>Job Queue</h4>
<FORM ACTION="<% $r->uri %>" METHOD=GET> 
<INPUT TYPE="hidden" VALUE="list" NAME="cmd">
<INPUT TYPE="hidden" VALUE="" NAME="act_ignore">
<& SELF:list_queue &>
<INPUT TYPE="submit" VALUE="Refresh Queue Listing">
Finished Jobs: <SELECT NAME="old_jobs">
% foreach my $num (qw/1 3 5 10 20 30 50 100/) {
    <OPTION VALUE="<%$num%>"<% $num eq $old_jobs ? ' SELECTED': ''%>><%$num%>
% }
</SELECT>
Ignore Actions of type: 
<SELECT NAME="act_ignore" SIZE=3 MULTIPLE>
% foreach my $act (sort keys %$action_types) {
    <OPTION VALUE="<%$act|h%>"<% grep(/^$act$/,@act_ignore) ? ' SELECTED' : ''%>><%$act%>
% }
</SELECT>
[<A HREF="<%$r->uri%>">Reset</a>]
</FORM>
<%args>
$dev      => undef
$dev_text => undef
$discover => undef
$cmd      => 'add'
$debug    => ''
$action   => ''
@logs     => ()
$nodes    => ''
$confirm  => ''
$old_jobs => 3
$port     => ''
@act_ignore => ()
</%args>
<%shared>
my $user      = $m->session->{user};
my $is_admin  = $m->session->{user_admin};
my $secure    = &is_secure;
my $domain    = $netdisco::CONFIG{domain};
my %actions = ( 
            # action       => [longname, confirm action,show]
             'discover'    => ['Discover Device',0,0],
             'discover_run'=> ['Discover Whole Network Starting from Device',1,0],
             'discover_new'=> ['Discover New Parts of Network from Device',1,0],
             'arpnip'      => ['ArpNip Device',0,1],
             'delete'      => ['Delete Device',1,1],
             'macsuck'     => ['MacSuck Device',0,1],
             'nodes-del'   => ['Delete Nodes',1,1],
             'nodes-arc'   => ['Archive Nodes',1,1],
             'refresh'     => ['Refresh Device',0,1],
             'expire_ips'  => ['Database Cleanup - Expire IPs [-I]',1,0],
             'graph'       => ['Regenerate Graph',1,0],
             'backup'      => ['Run Nightly Backup',1,0],
             'clean_nodes' => ['Database Cleanup - Nodes [-K]',1,0],
             'clean_alias' => ['Database Cleanup - Aliases [-k]',1,0]
           );
# Globals
my ($arg_dev,$arg_debug,$db_dev,$arg_act,$devices,$queue,$subaction,$action_types,$arg_dev_text,$arg_discover);
my $need_confirm = 0; my $commit = 0; my $odd = 0;
my %logs = ();
my $err =  '';
my @act_ignore_default = qw/portcontrol test/;
</%shared>
%#
%#
<%init>
# Send to https if not secure.
unless ($secure){
    my $url = url_secure($r->uri);
    $m->redirect($url);
}

# Send to login if not admin.
unless ($is_admin) {
    my $url = $m->interp->apply_escapes( $r->uri, 'u' );
    $m->redirect("login.html?done=$url");
}
# Move args to shared space for methods
$arg_dev = $dev; $arg_act = $action;
$arg_debug = $debug; $arg_discover = $discover; 
@act_ignore = @act_ignore_default unless scalar @act_ignore ;
%logs = map {$_ => 1} @logs;


#..................... Device Control .............................

# Load dev from db if given
if ($dev){
    $dev = getip($dev);
    my $dns = hostname($dev);
    $dns =~ s/\Q$domain\E//;
    $arg_dev_text = $dns if (defined $dev and defined $dns);
    $db_dev = sql_hash('device',['ip','dns','layers'],{'ip'=>$dev}) if $dev;
} elsif ($dev_text){
    # Resolve user entered device name to device_ip
    $dev=getip($dev_text);
    $arg_dev = $dev;
    $arg_dev_text = $dev_text if defined $dev;
    $db_dev = sql_hash('device',['ip','dns','layers'],{'ip'=>$dev}) if $dev;
} 

# Confirm Given Action if required
if ($cmd eq 'add' and $actions{$action}->[1] and $confirm ne 'ok') {
    $need_confirm++;    
}

# Maintenance Commands from admin.html
if ($cmd eq 'add' and $action =~ /^(expire_ips|graph|backup|clean_nodes|clean_alias)$/ and !$need_confirm){
    $dev = undef;
    $commit++;
}

# Refresh / MacSuck / Arpnip
if ($cmd eq 'add' and $action =~ /^(refresh|macsuck|arpnip)$/ and !$need_confirm){
    # Verify device exists.
    unless (defined $db_dev->{ip}){
        $err .= "Device ($dev) not found in Database.<BR>\n";
        $action = undef;
        $arg_dev = $dev = undef;
    }

    # Verify macsuck/arpnip is possible on device.
    my $layers = $db_dev->{layers};

    if ($action eq 'macsuck' and !&netdisco::has_layer($layers,2) ){
        $err .= "Device does not support mac_sucking.<BR>\n"; 
        $action = undef;
        $arg_dev = $dev = undef;
    }

    if ($action eq 'arpnip' and !&netdisco::has_layer($layers,3) ){
        $err .= "Device does not support arp_niping .<BR>\n"; 
        $action = undef;
        $arg_dev = $dev = undef;
    }

    # Add Entry to Queue
    $commit++ unless $err;
} 

# Delete
if ($cmd eq 'add' and $action eq 'delete' and $confirm eq 'ok'){
    # Verify device exists.
    unless (defined $db_dev->{ip}){
        $err .= "Device not found in Database.<BR>\n";
        $action = undef;
    }
    # Add to queue.
    unless ($err) {
        $err .= "Device $dev marked for deletion.<BR>\n";
        $action = $nodes eq 'ok' ? 'delete+nodes' : 'delete';
        $commit++;
    }
}

# Archive/Delete Nodes
if ($cmd eq 'add' and $action =~ /^nodes/ and $confirm eq 'ok'){
    # Verify device exists.
    unless (defined $db_dev->{ip}){
        $err .= "Device ($dev) not found in Database.<BR>\n";
        $action = undef;
        $arg_dev = $dev = undef;
    }
    # Port Only
    if ($port !~ /^\s*$/){
        my $port = sql_hash('device_port',['port'],{'ip'=>$dev,'port'=>$port});
        unless (defined $port and $port->{port}){
            $err .= "$actions{$action}->[0] - $dev - Port $port not found!<BR>\n";
            $action = undef;
            $arg_dev = $dev = undef;
        } else { 
            # Restict to Port 
           $subaction = $port->{port}; 
        }   
    }  

    $commit++ unless $err;
}

# Discover Devices
if ($cmd eq 'add' and $action =~ /^(discover|discover_new|discover_run)$/ and !$need_confirm){
    # Check input
    unless (defined $discover and length($discover)){
        $err .= "Please enter the device IP or DNS name to discover.<BR>\n";
        $discover = $discover = undef;
    } else {
        $subaction = $discover;
        $dev = undef;
        $discover = $discover = undef;
        $commit++;
    }
}

# Add to Queue
if ($commit) {
    $err .= "Action Queued - $action";
    $err .= " For Device $dev." if $dev;
    $err .= "<BR>\n";
    insert_or_update('admin',{},
                     {'device'=>$dev,'action'=>$action, 'status' => 'queued',
                      'username' => $user, 'debug' => ($debug eq 'yes' ? 1 : 0),
                      'subaction' => $subaction }
                    );
    $action = undef;
    $arg_dev = $dev = undef;
}

#............ Job Queue ............

# job queue is after device control in case we just added to it.

# Load device list, unless device provided.
$devices = sql_rows('device',['ip','dns'], undef, undef,'order by ip asc');

# Taint check (head between legs)
$old_jobs = 5 unless ($old_jobs =~ /^\d+$/);

# Fetch action types
$action_types = sql_column('admin',['distinct(action)','true']);

# Create NOT IN list if we are ignoring certain types.
my $where = {};
my @ignore = @act_ignore;
$ignore[0] = "!$ignore[0]" if scalar @ignore;
$where->{action} = [\@ignore] if scalar @ignore;

# Fetch running jobs
$where->{status} = [['queued','running']];
$queue = sql_rows('admin',['job','extract(epoch from entered) as entered','extract(epoch from finished) as finished',
                           'extract(epoch from started) as started','device','action','status','username'],
                  $where);

# Fetch done jobs.
$where->{status} = [['done','error']];
my $done = sql_rows('admin',['job','extract(epoch from entered) as entered','extract(epoch from finished) as finished',
                             'extract(epoch from started) as started','device','action','status','username'],
                    $where,undef,"order by entered desc limit $old_jobs");
push (@$queue,@$done);

# Log entries are fetched separately, as these can be rather large, and should
#  only be loaded if needed.
foreach my $item (@$queue){
    my $id = $item->{job};
    if (defined $logs{$id}){
        my $log = sql_scalar('admin',['log'],{'job'=>$id});
        $item->{log} = $log;
    }
}

</%init>
%#
%# err() - Prints out the error string if it exists.
%#
<%method err>
% return unless $err;
<h3><%$err%></h3>
</%method>
%#
%# confirm() - Creates a confirmation page for certain actions
%#
<%method confirm>
% my $act = $actions{$arg_act}->[0];
<h3>Confirm <%$act%> <% $arg_dev ? "of $arg_dev" : ''%></h3>
<FORM ACTION="<% $r->uri %>" METHOD=POST> 
<INPUT TYPE="HIDDEN" NAME="cmd" VALUE="add">
<INPUT TYPE="hidden" NAME="dev" VALUE="<%$arg_dev|h%>">
<INPUT TYPE="hidden" NAME="action" VALUE="<%$arg_act%>">
<INPUT TYPE="hidden" NAME="discover" VALUE="<%$arg_discover%>">
<INPUT TYPE="checkbox" NAME="confirm" VALUE="ok">
Check to Confirm - <%$act%>
% if ($arg_dev) {
 - <A HREF="device.html?ip=<%$arg_dev |u%>"><%$arg_dev%>
% }
</A>
<BR>
%# Action specific check options:
%#
%# Delete Device - Checkbox to Delete Nodes too
% if ($arg_act eq 'delete'){
<INPUT TYPE="checkbox" NAME="nodes" VALUE="ok"> Delete Nodes Too. 
% } 
%# Delete Nodes - Ability to select port
% if ($arg_act =~ /^nodes/) {
%   my $ports = sql_rows('device_port',['port'],{'ip'=>$arg_dev});
Restrict <%$act%> to
<SELECT NAME="port">
    <OPTION VALUE="" SELECTED>All Ports
%   foreach my $row (sort {$a->{port} cmp $b->{port}} @$ports){
%       my $port = $row->{port};
   <OPTION VALUE="<%$port|h%>"><%$port|h%> 
%   }
</SELECT>
%}
<BR>
<INPUT TYPE="checkbox" NAME="debug" VALUE="yes"<%$arg_debug? ' CHECKED' : ''%>>
Debug Output
<P>
<INPUT TYPE="submit" VALUE="<%$act%><% $arg_dev ? "- $arg_dev" : '' %>">
</FORM>
</%method>
%#
%# dev_control() - Prints out the device control menu form.
%#
<%method dev_control>
<h4>Device Control</h4>
<FORM ACTION="<% $r->uri %>" METHOD=POST> 
<INPUT TYPE="HIDDEN" NAME="cmd" VALUE="add">
<TABLE CELLSPACING=0 CELLPADDING=3 CLASS="box" border=0>
<TR>
    <TD><% $arg_dev ? '&nbsp;' : 'Choose Device :'%></TD>
    <TD><% $arg_dev ? '&nbsp;' : $m->comp('SELF:list_dev')%></TD>
    <TD ROWSPAN=2>Action : </TD>
    <TD ROWSPAN=2>
        <SELECT NAME="action" SIZE=4>
% foreach my $c (sort keys %actions){
%   next unless $c;
%   next unless $actions{$c}->[2];
            <OPTION VALUE="<%$c|h%>"><%$actions{$c}->[0]%>
% }
        </SELECT>
    </TD>
</TR>
<TR>
    <TD>Enter Device : </TD>
    <TD>
        <INPUT TYPE="TEXT" VALUE="<%$arg_dev%>" NAME="dev_text">
        <% defined $arg_dev_text ? "<BR><FONT SIZE=-1><TT>($arg_dev_text)</TT></FONT>" : '' %>
    </TD>
</TR>
<TR> 
    <TD COLSPAN=2>
        <INPUT TYPE="submit" VALUE="Queue New Job">
        [<A HREF="<%$r->uri%>">Reset</A>]
    </TD>
    <TD COLSPAN=2>
        Debug :
        <INPUT TYPE="checkbox" NAME="debug" VALUE="yes" <%$arg_debug ? 'CHECKED' : ''%>>
    </TD>
</TR>
</TABLE>
Use this box to control devices that are already in Netdisco's database.
</FORM>

<h4>Discover Devices</h4>
<FORM ACTION="<% $r->uri %>" METHOD=POST> 
<INPUT TYPE="HIDDEN" NAME="cmd" VALUE="add">
<TABLE CELLSPACING=0 CELLPADDING=3 CLASS="box" border=0>
<TR>
    <TD>Enter Device : <INPUT TYPE="TEXT" VALUE="<%$arg_discover%>" NAME="discover" TITLE="IP or Host Name">
    </TD>
    <TD><SELECT NAME="action" SIZE=1>
% foreach my $c (qw/discover discover_new discover_run/){
            <OPTION VALUE="<%$c|h%>"><%$actions{$c}->[0]%>
% }
        </SELECT>
    </TD>
</TR>
<TR> 
    <TD><INPUT TYPE="submit" VALUE="Queue New Job">
        [<A HREF="<%$r->uri%>">Reset</A>]
    </TD>
    <TD>Debug :
        <INPUT TYPE="checkbox" NAME="debug" VALUE="yes" <%$arg_debug ? 'CHECKED' : ''%>>
    </TD>
</TR>
</TABLE>
Use this box to add new devices to the network, or to re-add devices after deletion.
</FORM>
</%method>
%#
%# list_dev() - Create <SELECT> list for devices 
%#
<%method list_dev>
<SELECT NAME="dev" SIZE=8>
% foreach my $dev (sort {$a->{dns} cmp $b->{dns}} @$devices){
%   my $view = defined $dev->{dns} ? $dev->{dns} : $dev->{ip};
%   $view =~ s/\Q$domain\E//; 
            <OPTION VALUE="<%$dev->{ip}|h%>"><%$view%>
%}
        </SELECT>
</%method>
%#
%# list_queue() - List jobs in admin queue
%#
<%method list_queue>
% return unless scalar @$queue;
<TABLE WIDTH=100% CELLSPACING=0 CELLPADDING=2 BORDER=0> 
  <TR>
    <TH>Job</TH>
    <TH>Action</TH>
    <TH>Time</TH>
    <TH>Status</TH>
    <TH>View<BR>Log</TH>
% if (scalar keys %logs){
    <TH>Log</TH>
%}
  </TR>
<%perl>
foreach my $job (sort {$b->{entered} <=> $a->{entered} } @$queue){
    my $act    = $job->{action};
    my $entered = scalar localtime($job->{entered});
    my $start   = defined $job->{started} ? scalar localtime($job->{started}) : undef;
    my $end   = defined $job->{finished} ? scalar localtime($job->{finished}) : undef;
    my $time  = (defined $job->{started} and defined $job->{finished}) ?
        $job->{finished} - $job->{started} : undef;
    my $timestamp = defined $time ?
         sprintf("Ended: %s<BR> %-2.2f min.",$end,$time/60) 
         : undef;
    $timestamp = "Start: $start" if (! defined $timestamp and defined $start);
    $timestamp = "Queued: $entered" if (! defined $timestamp and ! defined $start);
    my $status = $job->{status};
    my $dev    = $job->{device};
    my $id     = $job->{job};
    $act .= " (<A HREF=\"device.html?ip=$dev\">$dev</A>)" if $dev;
</%perl>
  <TR CLASS="match-<% ++$odd%2 %>">
    <TD><%$id%> - <%$job->{username}%></TD>
    <TD><%$act%></TD>
    <TD><%$timestamp%></TD>
    <TD><%$status%></TD>
    <TD><INPUT TYPE="checkbox" NAME="logs" VALUE="<%$id%>"<% defined $logs{$id} ? ' CHECKED' : ''%>></TD>
% if (scalar keys %logs) {
    <TD>
%   if (defined $logs{$id} and !defined $job->{log}) {
    [ No Log Available ]
%   } elsif (defined $logs{$id} and defined $job->{log}) {
    <TEXTAREA COLS=50 ROWS=6 WRAP=OFF><%$job->{log}|h%></TEXTAREA>
%   } else {
    &nbsp;
%   }
    </TD>
% }
  </TR>
% }
</TABLE>
</%method>
<%method title>
- Admin Panel \
</%method>
%# $Id: admin_dev.html,v 1.10 2006/03/27 21:16:00 fenner Exp $
%# vim:syntax=mason
