<%doc>

Web interface for device discovery and updates

</%doc>
%
%
<%attr>
title   => 'Update Device' 
section => 'Management'
</%attr>
%
%
<%args>
$action
$device          => undef
$host            => undef
$version         => undef
$comstr          => undef
$other_comstr     => undef
$sec_name        => undef
$sec_level       => undef
$auth_proto      => undef
$auth_pass       => undef
$priv_proto      => undef
$priv_pass       => undef
$id              => undef
$sid             => undef
$insert          => undef
$owner           => undef
$used_by         => undef
$site            => undef
$contacts        => undef
$add_subnets     => 1
$subs_inherit    => 1
$pretend         => undef
$user            => $ui->get_current_user($r)
</%args>
%
%
%######################################################################
%#
%# Initialization
%# 
%######################################################################
<%init>
my $DEBUG = 0;

my $manager = $ui->get_permission_manager($r);
unless ( $manager && $manager->can($user, 'access_admin_section', 'updatedevice.html:new') ){
    $m->comp('/generic/error.mhtml', error => "You do not have permission to add new devices");    
}

my $o;
my $fqdn;
my %argv;
my $session;
my $guessed_user_ent;
my $guessed_site;
my $guessed_cl;
my $info;
my $default_owner;
my $default_cl;
my $logstr;

print "ARGS contains: <pre>", Dumper(%ARGS), "</pre>" if $DEBUG;

if( $action eq "discover" && ! $sid ) {
    eval {
	$session = $ui->mk_session();
    };
    if ( my $e = $@ ){
	$m->comp('/generic/error.mhtml', error => $e);
    }
}
if( $sid ) {
    eval {
	$session = $ui->get_session($sid);
    };
    if ( my $e = $@ ){
	$m->comp('/generic/error.mhtml', error => $ui->error);
    }
}

if ( $action eq "discover" ){

    if ( $device ){
	# We got a device id, so we're most likely updating
	my $o = Device->retrieve($device);
	unless ( $o ){
	    $m->comp('/generic/error.mhtml', error=>"Could not retrieve Device id: $device");
	}
	$argv{device} = $device;
	$argv{name}   = $o->fqdn;
	
	# Fetch SNMP info
	eval {
	    $info = $o->get_snmp_info();
	};
	if ( my $e = $@ ){
	    $m->comp('/generic/error.mhtml', error=>$e);
	}
	
    }
    elsif ( $host ){
	$host =~ s/\s*//g;
	
	$argv{version} = $version;

	if ( $version == 3 ){
	    foreach my $key ( qw(sec_name sec_level auth_proto auth_pass priv_proto priv_pass) ){
		$argv{$key} = $ARGS{$key} if defined $ARGS{$key};
	    }
	}else{
	    # Give preference to the community being passed
	    if ( $comstr eq "Other" ){
		$argv{communities} = [$other_comstr] if defined $other_comstr;
	    }else{
		$argv{communities} = [$comstr] if defined $comstr;
	    }
	}
	
	# Fetch SNMP info
	eval {
	    $info = Device->get_snmp_info(host=>$host, %argv);
	};
	if ( my $e = $@ ){
	    $m->comp('/generic/error.mhtml', error=>$e);
	}
	print "info contains: <pre>", Dumper(%$info), "</pre>" if $DEBUG;
	
	# Make sure we don't have a device by this name already
	if ( my $o = Device->search(name=>$host)->first ){
	    $argv{device} = $o->id;
	}
	
	if ( !$argv{device} ) {
	    # Looks like we have to create a new device
	    $argv{name} = $host;
	    
	    # Try to guess the user entity based on the subnet
	    # Note that we're using the first IP address found
	    # So it might not be totally accurate, especially for
	    # routers.
	  LOOP:  foreach my $int ( keys %{ $info->{interface} } ){
	      foreach my $ip ( keys %{ $info->{interface}->{$int}->{ips} } ){ 
		  my $mask = $info->{interface}->{$int}->{ips}->{$ip}->{mask};
		  if ( my $subnetaddr = Ipblock->get_subnet_addr(address=>$ip, prefix=>$mask) ){
		      if ( my $subnet = Ipblock->search(address=>$subnetaddr)->first ){
			  if ( my $user_ent = $subnet->used_by ){
			      $guessed_user_ent = $user_ent;
			      if ( my $cl = $user_ent->contactlist ){
				  $guessed_cl = $cl->id;
			      }if ( my @entsites = $user_ent->sites ){
				  $guessed_site = $entsites[0]->site;
			      }
			      last LOOP;  #just grab the first one
			  }
		      }
		  }
	      }
	  }

	    # Get the default owner entity from config
	    my $config_owner = Netdot->config->get('DEFAULT_DEV_OWNER');
	    $default_owner   = Entity->search(name=>$config_owner)->first;
	    
	    # If we could not determine it before, 
	    # try to guess site based on SNMP location
	    if ( ! $guessed_site ){
		if ( my $loc = $info->{syslocation} ){
		    if ( my $site = Site->search_like(name=>"%$loc%")->first ){
			$guessed_site = $site;
		    }
		}
	    }
	    
	    # Get the default contactlist from config
	    my $config_cl = $ui->config->get('DEFAULT_CONTACTLIST');
	    $default_cl = ContactList->search(name=>$config_cl)->first;
	}

    }else{
	$m->comp('/generic/error.mhtml', error => "Discovery needs either device id or hostname");
    }

    # Now store the SNMP info in the session
    $argv{info}      = $info;
    $session->{argv} = \%argv;

    
}elsif ( $action eq "update" ){

    # Add a string log appender 
    # Notice that we intentionally "eradicate" the appender and make sure the string
    # is not being used (wasting memory) except when this component is called.
    # We look it up before creating it in case this process ended abruptly earlier.
    if ( $logstr = Log::Log4perl::appender_by_name('updatedevice.html') ){
	    Log::Log4perl->eradicate_appender('updatedevice.html');
    }
    $logstr = Netdot::Util::Log->new_appender('String', name=>'updatedevice.html');

    my $logger = Netdot->log->get_logger('Netdot::Model::Device');
    $logger->add_appender($logstr);
    
    my $dns_logger = Netdot->log->get_logger('Netdot::Model::DNS');
    $dns_logger->add_appender($logstr);
    
    my $ip_logger = Netdot->log->get_logger('Netdot::Model::Ipblock');
    $ip_logger->add_appender($logstr);
    
    %argv = %{$session->{argv}};
    print "argv contains: <pre>",  Dumper(%argv), "</pre>" if $DEBUG;
    
    if ( exists $argv{device} ){

	unless ( $o = Device->retrieve($argv{device}) ){
	    $m->comp('/generic/error.mhtml', error=>"Could not retrieve Device id: $device");
	}
	
	my %uargs = (info=>$argv{info}, do_info=>1);
	
        unless( $uargs{name} = $argv{name} ){
            $uargs{name} = $o->fqdn;
        }
        $uargs{pretend} = 1 if $pretend;
	
	eval {
            #we use discover here because it will correct the RR for us (if it needs correcting), 
            #if the device has moved it calls snmp_update anyway, so its
            #really not that different than before.
	    $o = Device->discover(%uargs); 
	};
	
	if ( my $e = $@ ){
	    $m->comp('/generic/error.mhtml', error=>$e);
	}

    }else{
        $argv{name}         = $host           || "";
	$argv{contacts}     = $contacts       || "";
	$argv{owner}        = $owner;
	$argv{used_by}      = $used_by;
	$argv{add_subnets}  = $add_subnets;
	$argv{subs_inherit} = $subs_inherit;
	$argv{site}         = $site;
	eval {
	    $o = Device->discover(%argv);
	};
	if ( my $e = $@ ){
	    $m->comp('/generic/error.mhtml', error=>$e);
	}
    }
    $fqdn = $o->fqdn;

}#endif update

else{
    $m->comp('/generic/error.mhtml', error => "Unknown action: $action");
}

</%init>
    
%######################################################################
%#
%# User Interface
%# 
%######################################################################

<div id="sectiondetail">
 <div class="container">
   <div class="containerhead">
      Device: <strong><% $host %></strong>
   </div>

%if ( $action eq "discover" ){

%   my @allcls = ContactList->retrieve_all; 

    <& /generic/attribute_table.mhtml, field_headers=>["Description"], data=>[ $info->{sysdescription} ] &>

    <form name="netdotform" action="updatedevice.html" method="POST">
    <input type="hidden" name="sid" value="<% $session->{_session_id} %>">
    <input type="hidden" name="host" value="<% $host %>">
    <input type="hidden" name="action" value="update">

%     my (@field_headers, @cell_data) = ();

%     if ( ! $argv{device} ){ # We're inserting a Device for the first time
%

% push( @field_headers, "Owner:" );
<&| "/generic/HERE.mhtml" &>
           <select name="owner" id="owner">
           <option value="">-- Select --</option>
%          my @allents = Entity->retrieve_all; 
%          @allents = sort { $a->name cmp $b->name } @allents;
%          foreach my $ent (@allents){
%                if ( $default_owner && ($ent->id == $default_owner->id) ){
                   <option value="<% $ent->id %>" SELECTED><% $ent->name %></option>                
%                }else{
                   <option value="<% $ent->id %>"><% $ent->name %></option>
%                }
%          }
           </select>
           <a href="#" onClick="openinsertwindow('table=Entity&select_id=owner&selected=1&dowindow=1')">[new]</a>
</&>
% push( @cell_data, $_ );

% push( @field_headers, "Used by:" );
<&| "/generic/HERE.mhtml" &>
           <select name="used_by" id="used_by">
           <option value="">-- Select --</option>
%          my @allents = Entity->retrieve_all; 
%          @allents = sort { $a->name cmp $b->name } @allents;
%          foreach my $ent (@allents){
%                if ( $guessed_user_ent && ($ent->id == $guessed_user_ent->id) ){
                   <option value="<% $ent->id %>" SELECTED><% $ent->name %></option>                
%                }else{
                   <option value="<% $ent->id %>"><% $ent->name %></option>
%                }
%          }
           </select>
           <a href="#" onClick="openinsertwindow('table=Entity&select_id=used_by&selected=1&dowindow=1')">[new]</a>
</&>
% push( @cell_data, $_ );

% push( @field_headers, "Site:" );
<&| "/generic/HERE.mhtml" &>
           <select name="site" id="site">
           <option value="">-- Select --</option>
%          my @allsites = Site->retrieve_all; 
%          @allsites = sort { $a->name cmp $b->name } @allsites;
%          foreach my $site (@allsites){
%                if ( $guessed_site && ($site->id == $guessed_site->id) ){
                   <option value="<% $site->id %>" SELECTED><% $site->name %></option>
%                }else{
                   <option value="<% $site->id %>"><% $site->name %></option>
%                }
%          }
           </select>
           <a href="#" onClick="openinsertwindow('table=Site&select_id=site&selected=1&dowindow=1')">[new]</a>
</&>
% push( @cell_data, $_ );

% push( @field_headers, "Contacts:" );
<&| "/generic/HERE.mhtml" &>
           <select name="contacts" id="contacts" size="6" MULTIPLE>
           <option value="">-- Select --</option>
%          @allcls = sort { $a->name cmp $b->name } @allcls;
%          foreach my $cl (@allcls){
%                if ( $default_cl && ($cl->id == $default_cl->id) ){
                   <option value="<% $cl->id %>" SELECTED><% $cl->name %></option>
%                }else{
                   <option value="<% $cl->id %>"><% $cl->name %></option>
%                }
%          }
           </select>
	       Select all that apply
</&>
% push( @cell_data, $_ );

%################################################################
%# The following block only applies to routers
%################################################################
% if ( $info->{ipforwarding} ){
%    push( @field_headers, "Add new Subnets (if any)?:" );
<&| "/generic/HERE.mhtml" &>
%    if ( Netdot->config->get('ADDSUBNETS') ){
	<input type="checkbox" name="add_subnets" checked>
%    }else{
	<input type="checkbox" name="add_subnets">
%    }
</&>
%    push( @cell_data, $_ );

%    push( @field_headers, "Should new subnets <br>inherit device owner/user?:" );
<&| "/generic/HERE.mhtml" &>
%    if ( Netdot->config->get('SUBNET_INHERIT_DEV_INFO') ){
	<input type="checkbox" name="subs_inherit" checked>
%    }else{
	<input type="checkbox" name="subs_inherit">
%    }
</&>
%    push( @cell_data, $_ );
% }

%     }else{  # We're updating an existing Device

%###################################################################
%# Ask if changes should not be committed to the DB
%###################################################################
%    push( @field_headers, "Dry Run?:" );
<&| "/generic/HERE.mhtml" &>
	<input type="checkbox" name="pretend"> (Show operations and roll back DB changes)
</&>
%    push( @cell_data, $_ );

%    } # endif !$argv{device}

<& /generic/attribute_table.mhtml, field_headers=>\@field_headers, data=>\@cell_data &>

         <center>
             <input name="insert" value="Update" type="submit">&nbsp;
             <input type="button" name="cancel" value="Cancel" onClick="history.go(-1);">
         </center>
      </form>

%}elsif ( $action eq "update" ){
%      ##########################################################################
%      # We filter out the log output to get only lines belonging to this device
%      # This is because some other process might be logging to this same logger
%      ##########################################################################
%      my $log = $logstr->string() ;
%      my @lines  = split /\n/, $log;
%      my @output = grep /$fqdn/, @lines;
%      if ( @output ){
           <pre>
%          foreach my $line ( @output ){
<% $line %>
%          }
           </pre> <br />
%      }

       <b><a href="device.html?id=<% $o->id %>">[Go to <% $fqdn %>]</a></b>
%  }

 </div>
</div>

<%cleanup>
    if ( defined $logstr ){
        Log::Log4perl->eradicate_appender('updatedevice.html')
    }
</%cleanup>
