cc/td/doc/product/rtrmgmt/ciscoasu/nr/nr3-5
hometocprevnextglossaryfeedbacksearchhelp
PDF

Table of Contents

Nrcmd API

Nrcmd API

You can use the nrcmd command to interactively configure and control a Network Registrar cluster, or you can use it as a programming interface for another program or script. This chapter describes how to use the nrcmd command as an API (Application Programming Interface).

Connecting to Network Registrar

When you use the nrcmd command, you connect to a Network Registrar cluster to read and write configuration data, read state data, and perform control operations.

A Network Registrar cluster consists of the following:

Performing Authentication

When you log in to a cluster you are authenticated with a name and a password. The authentication protocol uses one-way hashes so that a password does not travel across the wire. In interactive mode, the nrcmd command prompts you for a valid username and password. You can also provide the username and/or password on the command line, in the environment, or in the Windows NT registry. (On Solaris, the Windows NT registry is emulated by files in the product configuration directories.)

Because you may not want to embed the administrator password in a command script, the environment variables and registry entries provide alternate locations with different visibility levels. The environment variables AIC_CLUSTER, AIC_NAME, and AIC_PASSWORD specify the cluster, administrator name and administrator password values. Similarly, the registry keys with the same names (AIC_CLUSTER, AIC_NAME, and AIC_PASSWORD) in the directory Software\American Internet\Network Registrar\2.0 of the HKEY_CURRENT_USER hive.

For more information about creating admin names and passwords, see the "Admin" section.

Choosing Scripting Techniques

Because nrcmd does a significant amount of processing at connect time, it is more efficient to perform multiple commands in a single session rather than initiating a distinct connection and login for each command. The simplest way to have a single nrcmd session perform multiple commands is to create a nrcmd batch file with one command per line, and redirect standard input from that file. A more complicated approach, but one that provides more control over the command sequence, is to run nrcmd from a controlling program and have that program send commands and read their status and output.

Using Nrcmd Batch Files

The simplest way to automatically perform multiple configuration commands is to create a batch file of nrcmd commands and have nrcmd execute them sequentially.

For example, to create a scope and add some reservations to it, you can type the following commands and store them in the file scope.txt:

scope demo1 create 24.10.2.0 255.255.255.0 
scope demo1 addReservation 24.10.2.1 1,6,0a:23:45:67:89:01 
scope demo1 addReservation 24.10.2.2 1,6,0c:23:45:67:89:02 
scope demo1 addReservation 24.10.2.3 1,6,0c:23:45:67:89:03 
scope demo1 addReservation 24.10.2.4 1,6,0a:23:45:67:89:04 
 

You can then run a single nrcmd session to execute all of these commands:

% nrcmd -b < scope.txt
 

For more information about the scope command, see the "Scope" section.

The advantage to using batch files is that they allow you to execute multiple configuration commands while only incurring the connection cost once. The disadvantage to using batch files is that you cannot add program logic between nrcmd commands. If a command (such as the initial scope creation in the previous example) fails, the batch file continues even though the subsequent commands are now useless.

Command Syntax

When you execute nrcmd commands that contain equal-signs, you have to quote them. For example, to use a single command to create a client-class name, type:

nrcmd -C cluster -N admin -P pwd "client MAC create client-class-name=asdf"

Adding Program Control

A more sophisticated method for automatically configuring and controlling Network Registrar is to have a program or script start a nrcmd session and communicate with the session through standard input and output.

To control nrcmd from another program, you need to start nrcmd from the controlling program and redirect standard input and output from nrcmd to file handles in the controlling program. The controlling program can then write commands to the input file handle and read results from the output file handle.

When running in batch mode, nrcmd reads a line of input at a time, and prints a new line after the prompt. This provides an easily parsed sequence of lines in response to any command:

File Locking

With regard to the file locking, because your perl script (or .bat file) is not being opened in interactive mode, it does not need a persistant database lock. You can have the GUI open (and hence, can have a lock on the database), and can still run a script to create a client.

Using Perl

The Perl language supports opening a child process with either its standard input or standard output provided by the parent script, but it does not allow both. On UNIX, the IPC::Open2 and IPC::Open3 modules in the Perl library provide file handles for standard input, output and error (with open3()).

The rest of this description assumes that you are running Perl5 on a Solaris platform.

You can use open2() or open3() from a Perl script to start a nrcmd session with Perl file handles for its standard input and standard output. After your script has started the session, it can send commands to the input file handle and read the subsequent result lines.

The Nrcmd.pm module provides both an example of the low-level Perl code to communicate with nrcmd, and a higher level Perl interface to one or more nrcmd sessions. The main interfaces to the Nrcmd.pm module are:

Tell the Nrcmd.pm module where the nrcmd process is installed. The default value for $install_dir is /opt/nwreg2.
Create a new nrcmd session connected to $cluster and authenticated with $user and $pass.
Find out if a nrcmd session object is still valid---is the child nrcmd process still running?
Have the child nrcmd process perform $cmd, and return the status code, full status line and result information.

Using an Interactive Shell with Nrcmd.pm

The following code example shows how to use the Nrcmd.pm module:

#!/usr/local/bin/perl
 
use Nrcmd;
 
$Nrcmd::nrcmd_path ='/opt/nwreg2/usrbin/nrcmd';
 
# create a nrcmd session
$session = new Nrcmd('localhost', 'admin', 'aicuser');
 
# check that we got a child process
# and print out the startup banner
if ($session->isValid()) {
    print "$session->{'banner'}\n";
    $session->doCmd('session set default-format=script');
} else {
    print "invalid session: '$session->{'banner'}'\n";
}
 
# loop through reading a line from the terminal,
# sending it as a command to the nrcmd session,
# and printing the resulting status and data.
while ($session->isValid()) {
    # print the prompt
    print "pl-nrcmd> ";
 
    # read a line of input, and strip the trailing new line
    my $line = <STDIN>;
    chomp($line);
 
    # evaluate the expression by sending it to nrcmd
    ($s, $l, $r) = $session->doCmd($line);
 
    # print the status and result
    print "($s, '$l')\n" if ($s);
    print "$r\n";
 
	# continue,
	# the SIGCHLD handler in Nrcmd.pm will catch the nrcmd process
	# going away, destroy the object,
	# and then isValid() will return 0
	# and we will fall out of this loop
}

Creating Policies and Scopes with Nrcmd.pm

The following script demonstrates how you can create scopes for subnets 10 through 39 and the associated policy. For more information about the scope command, see the "Scope" section. For more information about the policy command, see the "Policy" section.

#!/usr/local/bin/perl
 
use Nrcmd;
 
$Nrcmd::nrcmd_path ='/opt/nwreg2/usrbin/nrcmd';
 
# create a nrcmd session
$session = new Nrcmd('localhost', 'admin', 'aicuser');
 
# check that we got a child process,
# and print out the startup banner
 
if ($session->isValid()) {
    $session->doCmd('session set default-format=script');
    print "got valid nrcmd session\n";
} else {
    print "invalid session: '$session->{'banner'}'\n";
}
 
# now make policies and scopes for subnets 10 to 39
for ($i = 10; $i < 30; $i++) {
    ($s, $l, $r) = $session->doCmd("policy net-$i create");
    print "policy net-$i create --> $l\n";
 
    if ($s == 100 || $s == 314) {
	$cmd = "scope net-$i create 128.103.$i.0 24 policy=net-$i";
	($s, $l, $r) = $session->doCmd($cmd);
	print "scope net-$i create --> $l\n";
    } else {
	print "skipping scope net-$i since policy create failed\n";
    }
}

Language Libraries

The following is the nrcmd command module written in Perl.

Perl---Nrcmd.pm

package Nrcmd;
 
=head1 NAME
 
Nrcmd - manipulate Network Registrar through the nrcmd CLI
 
=head1 SYNOPSIS
 
    use Nrcmd;
 
    $session = new Nrcmd('localhost', 'admin', 'aicuser');
    ($stat, $sline, $result) = 
     $session->doCmd('scope create foo 10.1.0.0 255.255.0.0');
    $session->doCmd('exit');
 
    # etc.
 
=head1 DESCRIPTION
 
The Nrcmd module provides an interface to one or more Network Registrar clusters through the nrcmd CLI process.  A secondary purpose is to provide an example of controlling nrcmd from another process.
 
=cut
 
# Class (package) variables:
#
#  %pid_map  
#   - maps pid to the Nrcmd object so that
# we can clean up the object in the SIGCHLD handler
#
#  $nrcmd_path
#   - the path to the nrcmd binary
 
# Public object methods:
#   new Nrcmd(cluster, user, password)
#    - create a nrcmd session
#   
#   doCmd(command)
#    - peform a single command and return the status and result
#
 
#
# Private object methods:
#   _connect(cluster, user, password)
#    - starts up a session with USER and PASSWORD as authentication
#    - returns the status and startup banner, or error
#
#   _read_to_prompt()
#    - read status and result values until a prompt
#
#   _delete()
#    - closes the objects read and write file handles and 
#
#   _exit(void)
#    - a simple wrapper around doCmd('exit')
#
 
# we use the IPC and Symbol modules from the standard library,
# so require them here.
use IPC::Open2;
use Symbol;
 
@EXPORT = qw(new doCmd);
 
$VERSION = 0.1;
 
# the path to the installed nrcmd binary
# you can set this with:
#  $Nrcmd::nrcmd_path = <non-default install path>
 
$nrcmd_path = "/opt/nwreg2/usrbin/nrcmd";
 
# at module startup, add a signal handler for SIGCHLD
# to delete (invalidate) session object associated
# with child nrcmd process.
#
# XXX: this probably does not play well with
# other SIGCHLD handlers
 
BEGIN {
    # set the 
    $SIG{CHLD} = sub { 
	my $pid = wait();
	my $obj = $pid_map{$pid};
 
	if ($obj) {
		    	$obj->_delete();
	    undef $pid_map{$pid};
	}
    }
}
 
# create a new Nrcmd session object
#  new Nrcmd(<cluster>, <user>, <password>)
 
sub new {
    my $class = shift;
    my $cluster = shift;
    my $user = shift;
    my $password = shift;
    my $self = {};
    bless $self, $class;
    $self->_connect($cluster, $user, $password);    
    return $self;
}
 
# _delete()
# probably incorrect destructor, but at least mark session object
# as not having a process, and close off its read and write file
# handles
sub _delete {
    my $self = shift;
    $self->{'pid'} = 0;
    close($self->{'rfh'});
    close($self->{'wfh'});
}
 
# isValid()
#   check to see if a session object is valid
sub isValid {
    my $self = shift;
    return ($self->{'pid'} != 0);
}
 
# _connect(cluster, user, pass)
# connect a session object to the given CLUSTER with the given
# USER name and password PASS.
#
# XXX: this does not return failed connection information very
# well
 
sub _connect {
    my $self = shift;
    my $cluster = shift;
    my $user = shift;
    my $pass = shift;
 
    # create file handle objects
    my $rfh = $self->{'rfh'} = gensym();
    my $wfh = $self->{'wfh'} = gensym();
 
    # build up the nrcmd command line
    my $cmdline = "$nrcmd_path -b";
    $cmdline .= " -C $cluster" if ($cluster);
    $cmdline .= " -N $user" if ($user);
    $cmdline .= " -P $pass" if ($pass);
 
    # spawn the nrcmd process
    my $pid = $self->{'pid'} = open2($rfh, $wfh, $cmdline);
 
    if ($pid) {
	$pid_map{$pid} = $self;
	my ($s, $l, $r) = $self->_read_to_prompt();
	$self->{'banner'} = $r;
    }
    return $pid;
}
 
# simple utility to wrap exit
sub _exit {
    my $self = shift;
    $self->doCmd('exit');
}
 
# perform a command in the given session,
# return the status code, the complete status line
# and any result lines
 
sub doCmd {
    my $self = shift;
    my $cmd = shift;
    my $wfh = $self->{'wfh'}; 
 
    # send the command line to the nrcmd process
    print $wfh "$cmd\n";
 
    # parse the result and return the status and data
    return $self->_read_to_prompt();
}
 
# read up to 'nrcmd> ' prompt,
# return the status code, the complete status line and any result lines.
# ignore any lines before status line.
 
sub _read_to_prompt {
    my $self = shift;
    my $rfh = $self->{'rfh'};
    my $line = "";
    my ($status, $sline, $rval);
 
    while (1) {
	$line = <$rfh>;
	# stop on EOF
	last unless $line;
 
	# stop on prompt line
	last if ($line =~ m/^nrcmd>\s$/);
	
	# look for status if we haven't seen the status line
	if (!$status) {
	    chomp($line);
	 if ($line =~ /^[0-9]+/) {
		($status) = $line =~ /^([0-9]+)/;
		$sline = $line;
	    }
	    next;
	}
 
	# if we have a status, collect output
	$rval .= $line;
	$line = "";
    }
    return ($status, $sline, $rval);
}
 
1; # to make require happy
 

hometocprevnextglossaryfeedbacksearchhelp
Posted: Thu Feb 3 10:33:57 PST 2000
Copyright 1989 - 2000©Cisco Systems Inc.