AXP 1.6 Developer Guide
CLI Plug-in Applications

Table Of Contents

CLI Plug-in Applications

CLI Plug-in Distribution Service

CLI Plug-in Application Components

Prepackaging the CLI Plug-in

Packaging a CLI Plug-in Application

Package the CLI Plug-in Separately from the Application

Bundle the CLI Plug-in with the Application

Installing a CLI Plug-in Application

Activating a CLI Plug-in Application

Activating a CLI Plug-in Application: Example

XML DTD File

DTD Introduction

Occurrence Operators

Element Choice

CLI DTD

Elements and Attributes

cli_grammar

mode

pattern

type

help

param

cmd

action

type

paginate

pipehelp

class

interrupt-timeout

Type Regex

CLI Plug-in Action APIs

eval: CLI plug-in Action API

evalError: CLI plug-in Action API

Supporting the no Prefix

CLI Plug-in Distribution Listener APIs

CLI Plug-in Errors

Interrupting Action Invocation

Simultaneous CLI plug-in Invocation

CLI Plug-in Application: Example

Health Status

Package Name

Show Time Application: Example

XML Script: Example

Action Class: Example

Starting a Listener from the Application: Example

Building and Testing: Example

Prepackaging the CLI Plug-in: Example


CLI Plug-in Applications


You can create Cisco AXP CLI plug-in to add a new command to the commands in the Cisco AXP CLI.

CLI plug-in application development:

CLI Plug-in Distribution Service

CLI Plug-in Application Components

CLI plug-in application tasks:

Prepackaging the CLI Plug-in

Packaging a CLI Plug-in Application

Installing a CLI Plug-in Application

Activating a CLI Plug-in Application

CLI plug-in reference information:

XML DTD File

CLI Plug-in Action APIs

Supporting the no Prefix

CLI Plug-in Distribution Listener APIs

CLI Plug-in Errors

Interrupting Action Invocation

Simultaneous CLI plug-in Invocation

Examples of simple CLI plug-in applications:

CLI Plug-in Application: Example

CLI Plug-in Distribution Service

The Cisco AXP CLI plug-in distribution service (axp-cli-plugin.<platform>.<version>.pkg) is a Cisco add-on package that provides the necessary libraries to distribute CLI plug-ins from the Cisco AXP CLI server to your application. For further details, see the "Cisco AXP Optional Features" section on page 25.

CLI Plug-in Application Components

The required components for integrating a CLI plug-in command into Cisco AXP are described in Table 105.

Table 105 CLI Plug-in Application Components

CLI Plug-in Component
Description

XML definition file

Defines the syntax of the command entered by the user. The XML for the command must adhere to the Data Type Definition (DTD) shown in the "Elements and Attributes" section.

Action class

A Java class, C class, or Bash script that runs when the user enters a CLI command that is defined in the XML definition file.

Note The CLI plug-in action must be the same language as the corresponding CLI plug-in application (distribution listener).

Java: When writing an action script (class) using Java, compile the class into <action name>.class.

C: When writing an action script (class) using C, compile the class into a shared library called <action name>.so.

Bash: When writing an action script using a Bash Shell script, <action name>.sh, note that only an integer value may be returned indicating the exit status. There is no support for returning messages for display by the CLI console.

Application

Starts a CLI VM thread startCLIDistributionVMThread that listens to user commands. Only if the application is running will the thread be able to listen and respond to CLI commands entered by the user.

When the user enters a CLI command defined in the XML definition file, startCLIDistributionVMThread invokes the corresponding action class.


Figure 15 shows these three CLI plug-in components, which are set up to process the show time command.

Figure 15 Cisco AXP CLI Plug-in Service

Prepackaging the CLI Plug-in

The CLI plug-in application must be prepackaged before running the packaging tool. For more information on packaging the plug-in, see the "Packaging a CLI Plug-in Application" section.

Prepackaging, using the CLI Plug-in SDK Packaging Tool, is dependent on setting up the data correctly in the directory sdk/tools/custom_cli/.

Each of the required directory components is listed below and then described in Table 106.

sdk/tools/custom_cli/
actions/
definitions/
internal/
cli_plugin.config
cli_plugin.py
cli_grammar.dtd


Note cli_plugin.py requires Java SDK version 1.4.2 or above to be installed on the development machine.


Table 106 CLI Plug-in SDK Packaging Tool Components

Component
Description
actions/

Compiled CLI plug-in action classes.

definitions/

CLI plug-in definitions.

internal/

Internal files used by the tool.

Note These files must not be modified.

cli_plugin.config

Configuration file.

cli_plugin.py

Executable file that packages the CLI plug-in application.

cli_grammar.dtd

Data Type Definition (DTD) file.

Note This file must not be modified.


To prepackage the CLI plug-in application perform the following steps.


Step 1 Copy the action file into the directory actions/ .

Step 2 Copy CLI plug-in definition files into the directory definitions/.


Note Files in the directory "internal/" must not be modified.


Step 3 Edit the configuration file cli_plugin.config. See Table 107.

Table 107 Configuration File Components

Component
Description

file

CLI plug-in definitions file, located in the directory definitions/

javapath

Path to the directory Java SDK bin/

vm

Name of the application. This name must match the name provided later in the application packaging tool. See the "Package Name" section.

proj_src

Root directory from which this product will be prepackaged.

If proj_src argument is specified, your project file is moved to directory /source/showtimeapp/build, ready for packaging.

If proj_src argument is not specified, your project file is created in file showtime.tar in /source/showtimeapp/build. Later, during packaging, you will need to untar showtime.tar using for example:

tar xvf showtime.tar -C /source/showtimeapp/build

Note If you choose to extract the contents of the tar file using an extractor tool for Windows, such as WinZip, you must first disable CR/LF conversion of tar files in the tool. (For example, in WinZip 9.0 select Configuration > Miscellaneous and uncheck "TAR file smart CR/LF conversion".)


Step 4 Run the CLI plug-in SDK packaging tool to package the definitions and actions.

To run the executable packaging tool, (cli-plugin.py), enter:

python cli-plugin.py

If the tool runs successfully, a tar file of the application is created in the output/ directory.

Step 5 Move the tar file to the source directory where the packaging tool runs.

Moving the tar File: Example

This example extracts the contents of the CLI plug-in tar file to the source directory where the packaging tool runs, and then deletes the tar file.

#cp output/showtime.tar /tmp/proj_dir/src
#cd /tmp/proj_dir/src
#tar xf showtime.tar
#rm showtime.tar

Prepackaging of the CLI plug-in is now complete.

The next stage is packaging. See the "Packaging a CLI Plug-in Application" section.


Packaging a CLI Plug-in Application

Check that the CLI plug-in prepackaged files have been copied into the /source/showtime/build directory. (See the "Prepackaging the CLI Plug-in: Example" section.) If the CLI plug-in's prepackaged files are in a tar file, extract them to the package directory. For example, use the following command to untar the showtime.tar file:

tar xvf showtime.tar -C /source/showtimeapp/build


Note If you choose to use an extractor tool designed for Windows, such as WinZip, you must disable CR/LF conversion of tar files. (For example, in WinZip 9.0 select Configuration > Miscellaneous and uncheck "TAR file smart CR/LF conversion".)


To package the application, see Packaging the Application, page 205 and the "Packaging Tool" section on page 132.

The CLI plug-in can be installed on Cisco AXP in the following two ways:

Package the CLI Plug-in Separately from the Application

Bundle the CLI Plug-in with the Application

Package the CLI Plug-in Separately from the Application

Install axp-cli-plugin.<platform>.<version>.pkg separately onto Cisco AXP.

Package the application with a dependency of the SSID of the axp-cli-plugin.<platform>.<version>.pkg. For further information, see "Packaging the Application" section on page 205 and the "Packaging Tool" section on page 132.

Install the application package onto Cisco AXP.

Bundle the CLI Plug-in with the Application

Package the application with a dependency of the SSID of the axp-cli-plugin.<platform>.<version>.pkg —see the "Packaging Tool".

Bundle the axp-cli-plugin.<platform>.<version>.pkg with the application package—use the Bundling Tool.

Install the bundle onto Cisco AXP.

Installing a CLI Plug-in Application

To install the CLI plug-in application, see the "Installing and Upgrading Software" section in Cisco AXP User Guide.

Activating a CLI Plug-in Application

To invoke a CLI plug-in application on the service module, in application service EXEC mode:

app-service <application name>

To invoke a CLI plug-in command, see the "CLI Plug-in Invocation" section in
Cisco AXP User Guide.

Activating a CLI Plug-in Application: Example

In the "Show Time Application: Example" section a plug-in for the command show time is created. To invoke this CLI plug-in:

app-service showtime

To display current time on the Cisco AXP service module:

show time

XML DTD File

A CLI command for a CLI plug-in written by a third-party is defined using XML. The XML must conform with an XML Document Type Definition (DTD) file. The DTD file allows you to plug a CLI plug-in application into the Cisco AXP CLI server.

For an explanation of how to define a CLI command using an XML DTD file, and the individual action classes invoked for the CLI command, refer to the start of this CLI Plug-in Applications section.

To find out more about DTD files the following website provides some general information: http://www.w3schools.com/dtd/default.asp.

DTD Introduction

In a DTD, the declarations for elements, attributes, and entities are prefaced in the same way, with an opening angle bracket followed by an exclamation mark: <!. After the exclamation mark comes one of three keywords written in all capitals—ELEMENT, ATTLIST, or ENTITY—that specify the type of declaration.

The syntax of the ELEMENT is:

<!ELEMENT element-name (child1,child2,...)>

, where child1, child2 are child elements of element-name.

The syntax of ATTLIST is:

<!ATTLIST element-name attribute-name attribute-type default-value>

The ATTLIST keyword is followed by the name of the element element-name for which the attributes are being defined and the list of attributes.

Occurrence Operators

The child elements of ELEMENT are shown above as: "(child1,child2,...".

The element child1 indicates there is exactly one occurrence of the child1 element. Use the following operators to control if an element is optional and how many elements occur together.

The question mark (?), which makes an element optional but not repeatable: the element may be used once or not at all. For example, (child1?).

The plus sign (+), which makes an element not optional and repeatable: the element must be used at least once. For example, (child1+).

The asterisk (*), which makes an element optional and repeatable: the element may be used any number of times or not at all. For example, (child1*).

Element Choice

You may nest a choice of elements by placing them in parentheses and separating them by a vertical bar. For example, (e1|e2) indicates an occurrence of either element e1 or element e2.

CLI DTD

The CLI DTD file is used to define the format of the XML that specifies a CLI command. This DTD file is tools/custom_cli/cli_grammar.dtd, within the Cisco AXP SDK.

<?xml version="1.1" encoding="UTF-8" ?>
<!ELEMENT cli_grammar (mode)+>
<!ELEMENT mode (pattern, (cmd)*)+>
<!ELEMENT pattern (#PCDATA)>
<!ATTLIST pattern type (id|regex|help) "id">
<!ELEMENT cmd ((pattern,(help)?), ((param)*),action)>
<!ELEMENT help (#PCDATA)>
<!ELEMENT param (pattern,(help)?)+>
<!ELEMENT action ((class)?, (interrupt-timeout)?)>
<!ATTLIST action
    type (default) "default"
    paginate (yes|no) "no"
    pipehelp (yes|no) "no">
<!ELEMENT class (#PCDATA)>
<!ELEMENT interrupt-timeout (#PCDATA)>

Elements and Attributes

The elements and attributes of the CLI DTD are explained as follows:

cli_grammar

mode

pattern

type

help

param

cmd

action

type

paginate

pipehelp

class

interrupt-timeout

cli_grammar

The cli_grammar element defines the top level document type for CLI XML files. All CLI XML files must start by declaring this element and specifying the "cli_grammar.dtd" definitions file.

<!ELEMENT cli_grammar (mode)+>

Each cli_grammar element consists of one or more mode elements.

<!DOCTYPE cli_grammar SYSTEM "cli_grammar.dtd">
<cli_grammar>
	<!--  The contents of the CLI XML file are place here -->
</cli_grammar>

mode

<!ELEMENT mode (pattern, (cmd)*)+>

There are one or more mode elements. Applications must define at least one mode element within the XML file. The mode element defines the CLI mode to which the subsequent XML elements will apply.

Each mode element contains one pattern element and zero or more cmd elements.

The pattern element has two type attribute values: exec and config, which represent the two common CLI modes.

mode: Example

<cli_grammar>
	<!--  Place valid mode elements here -->
	<mode>
		 <pattern type="id">exec</pattern> 
		...
	</mode>
		...
	<mode>
		 <pattern type="id">config</pattern>
		...
	</mode>

</cli_grammar>


pattern

<!ELEMENT pattern (#PCDATA)>

There is one pattern element, containing parsed character data (#PCDATA).

The parsed character data in the pattern element defines a name string used by the CLI for token matching. The pattern element is used within two different elements in the CLI XML:

1. pattern element within the mode element—defines the "CLI mode" section

2. pattern element within the cmd element—defines the "CLI Token String" section

CLI mode

In the case of a pattern element defined within the mode element, the name specified in the pattern element defines the name of the CLI mode to which the subsequent XML elements apply. The following example uses the pattern element to declare the CLI "exec" mode.

CLI mode: Example

<cli_grammar>
	<mode>
		<pattern>exec</pattern>
		<!--  Place additional mode elements here -->
	</mode>
</cli_grammar>


CLI Token String

The pattern element can also be declared within the cmd element. The pattern declares the token string to be matched by the CLI parser.

The following example shows the pattern element is used to declare the CLI token string "show". The "show" command is used in "exec" mode. The CLI server looks for an exact match of the token string defined in the pattern element.

CLI Token String: Example

<cli_grammar>
	<mode>
		<pattern>exec</pattern>
		<cmd>
			<pattern>show</pattern>
		</cmd>
		<!--  Place additional mode elements here -->
	</mode>
</cli_grammar>

type

type is an attribute of the pattern element.

<!ATTLIST pattern type (id|regex|help) "id">

type has three possible values which describe the pattern:

1. type="id" Defines the exact keyword string.

As "id" is the default attribute value, the following two DTD pattern element definitions are identical:

<pattern type="id">trace</pattern>

<pattern>trace</pattern>

2. type="regex" Defines a Perl5 regular expression. See http://perldoc.perl.org/perlre.html. Example:

pattern type="regex">[abc]</pattern>

3. type="help" Defines the token displayed in place of a regular expression when the "?" help is entered on the command line. Extra text is defined using a help element.

type attribute: Example:

	<cli_grammar>
	<mode>
		<pattern>exec</pattern>
		<cmd>
			<pattern type="id">show</pattern>
			<pattern type="regex">[abc]</pattern>
			<!—Specifies the help WORD for display in place of the regex -->
			<pattern type="help">A-B-C</pattern>
			<help>Select A or B or C</help>
		</cmd>
	</mode>
	<!-- Place additional mode elements here -->
	</cli_grammar>

Enter show? to display:

A-B-C Select A or B or C

help

<!ELEMENT help (#PCDATA)>

There is one occurrence of the help element, containing parsed character data (#PCDATA).

The element help defines the position sensitive help text that will appear on the console in response the `?' entered at the command line. The help element is associated with the previous pattern element in the CLI XML. We recommend that every pattern element have an associated help pattern specified to provide meaningful online help information.

The following lines show the help that appears for the exec mode command "show user".

hostname> ?
show 			Show running system information

hostname> show?

user 			Display user information
hostname>

The XML supporting the above help output is:

<cli_grammar>
	<mode>
		<pattern type="id">exec</pattern>
		<prompt></prompt> <!--no prompt for exec mode-->
		<cmd>
			<pattern type="id">show</pattern>
			<help>Show running system information</help>
			<param>
				<pattern type="id">user</pattern>
			<help>Display user information</help>
			</param>
		</cmd>
	</mode>
	<!-- Place additional mode elements here -->
</cli_grammar>

param

<!ELEMENT param (pattern,(help)?)+>

There are one or more param elements, with one child pattern element and
zero or one child help elements.

The param element defines keywords/tokens on the CLI command line in addition to the primary keyword. Each cmd element defines a complete CLI command line which will consist of the primary keyword pattern element optionally followed by zero or more param elements each specifying their own keyword pattern elements.

The following example has the minimum number of definitions required to construct the EXEC mode command line "turn on the lights".(To make the example easier to understand, help elements, as well as optional elements and attlists have been removed.) Note that the primary keyword is defined by:

			<pattern type="id">turn</pattern>

prior to the param elements which define the remaining keywords on the command line.

<cli_grammar>
	<mode>
		<pattern type="id">exec</pattern>
		<prompt></prompt> <!--no prompt for exec mode-->
		<cmd>
			<pattern type="id">turn</pattern>
			<param>
				<pattern type="id">on</pattern>
			</param>
			<param>
				<pattern type="id">the</pattern>
			</param>
			<param>
				<pattern type="id">lights</pattern>
			</param>
			<action>
			<class>com.home.lights.exec_lights_on</class>
			</action>
		</cmd>
	</mode>
	<!-- Place additional mode elements here -->
</cli_grammar>

cmd

<!ELEMENT cmd ((pattern,(help)?), ((param)*,action)>

The cmd element contains an optional child help element, zero or many param elements, and one action element.

The cmd element is the core building block for the CLI command definition. The cmd element is used to construct CLI parser nodes within the CLI server. The type of CLI parser node and the node's behavior is derived from the child elements of the cmd element.

cmd: Example 1

Defines the CLI command "show user database" and a CLI eval( ) handler to the com.cisco.aesop.cli.commands.exec_show_user_database.class class.

The CLI server is instructed to enable pagination during the formatting of the output of the command and the CLI server is instructed to enable the use of the pipe "|" text search mechanism. Refer to the paginate attribute within the action element.

<cli_grammar>
	<mode>
		<pattern type="id">exec</pattern>
		<prompt></prompt> <!--no prompt for exec mode-->
		<cmd>
			<pattern type="id">show</pattern>
			<help>Show running system information</help>
			<param>
				<pattern type="id">user</pattern>
				<help>Display user information</help>
			</param>
			<param>
				<pattern type="id">database</pattern>
				<help>Display all the CLI commands</help>
			</param>
			<action paginate="yes" pipehelp="yes">
				<class>com.cisco.aesop.cli.commands.exec_show_user_database.class</class>
			</action>
		</cmd>
	</mode>
	<!-- Place additional mode elements here -->
</cli_grammar>

cmd: Example 2

This example defines a CLI configuration command "hostname <name>". It defines the CLI eval( ) handler for this CLI command to be class com.cisco.aesop.platform.conf_hostname.class.

The hostname entered at the command line is accepted as a regular expression meeting the rule defined below, and a "?" help response is provided for each keyword on the command line including the regular expression.

<cli_grammar>
	<mode>
		<pattern type="id">config</pattern>
		<prompt>(config)</prompt> 
		<cmd>
			<pattern >hostname</pattern>
			<help>set the system name</help>
			<param>
				<pattern type="regex">[a-zA-Z][-a-zA-Z0-9]*[a-zA-Z0-9]/pattern>
				<pattern type="help">name</pattern>
				<help>hostname not including the domain</help>
			</param>
			<action>
				<class>com.cisco.aesop.platform.conf_hostname.class</class>
			</action>
		</cmd>
	</mode>
	<!--  Place additional mode elements here -->
</cli_grammar>

action

<!ELEMENT action ((class)?, (interrupt-timeout)?)>

One action element contains an optional class and optional interrupt-timeout element.

The element action defines the action the CLI server will take when a CLI command match is declared by CLI parser.

type

type is an attribute within the action element.

<!ATTLIST action type (default) "default" paginate (yes|no) "no" pipehelp (yes|no) "no">

The type attribute currently only supports the default attribute-type.

The type attribute may be expanded in the future to support additional action element types. At present, you can leave the type attribute out of the CLI XML action element definitions.

paginate

paginate is an attribute within the type element.

<!ATTLIST action type (default) "default" paginate (yes|no) "no" pipehelp (yes|no) "no">

The paginate attribute instructs the CLI server to format the text output from the action class eval( ) handler method. The CLI server breaks the output text stream every 24 lines and displays the "-- More --" message to the user. The user can then press any key to display the next page of output.

paginate: Example

The following example shows how to create a command ("show parser commands") which specifies pagination of the output. The command invokes the eval( ) method in the handler class com.cisco.aesop.cli.commands.show_commands.class.

	<cmd>
		<pattern type="id">show</pattern>
		<help>Show running system information</help>
		<param>
			<pattern type="id">parser</pattern>
			<help>Display parser information</help>
		</param>
		<param>
			<pattern type="id">commands</pattern>
			<help>Display all the CLI commands</help>
		</param>

		<action paginate="yes">
			<class>com.cisco.aesop.cli.commands.show_commands.class</class>
		</action>
	</cmd>

pipehelp

pipehelp is an attribute in the type element.

<!ATTLIST action type (default) "default" paginate (yes|no) "no" pipehelp (yes|no) "no">

The action element supports the pipehelp attribute. The pipehelp attribute instructs the CLI server to add the pipe `|' token to the end of the command line. The pipe filters the text that is output from the eval( ) method in the handler class. (The handler class in the example below is com.cisco.aesop.cli.commands.show_commands.class.)

Pipe filters:

begin—Begin with the line that matches.

exclude—Exclude the lines that match.

include—Include the lines that match.

page—Paginate output (--More--).

pipehelp: Example

This example shows how to create a command which will implement the pipe feature.

The following example command is "show parser commands".


	<cmd>
		<pattern type="id">show</pattern>
		<help>Show running system information</help>
		<param>
			<pattern type="id">parser</pattern>
			<help>Display parser information</help>
		</param>
		<param>
			<pattern type="id">commands</pattern>
			<help>Display all the CLI commands</help>
		</param>
		<action pipehelp="yes">
			<class>com.cisco.aesop.cli.commands.show_commands.class</class>
		</action>
	</cmd>

Example:

	hostname> show parser commands | ?
		begin Begin with the line that matches
		exclude Exclude lines that match
		include Include lines that match
		page Paginate output (--More--) 

The output from "show parser commands" is piped through one of the filter types: begin, exclude, include, or page.

Example:

	hostname> show parser commands | begin "d"

"show parser commands" invokes the eval( ) method in the handler class com.cisco.aesop.cli.commands.show_commands.class.

Each line of the output from the command is piped through "begin" filter type—in this example, only allowing commands starting with the letter "d".

class

<!ELEMENT class (#PCDATA)>

The class element, which is a child of the action element, specifies the handler class containing the eval( ) function/method invoked when the corresponding CLI command is recognized by the CLI parser. The name of the handler class contains the fully specified domain and class name (for example, com.cisco.aesop.service.handler.class). As a naming convention, we recommend that the mode of the CLI command is included in the class name. This prevents name-space collisions. For example, the "exec" mode is part of the name of the following class: com.cisco.aesop.service.exec_handler.class

class: Example

This example shows the class element used within the action element to define the eval( ) handler for the CLI command. The CLI command is "show users", and the class element is com.cisco.aesop.exec_show_users.class.

	<cmd>
		<pattern type="id">show</pattern>
		<help>Show running system information</help>
		<param>
			<pattern type="id">users</pattern>
			<help>Display user information</help>
		</param>
		<action>
			<class>com.cisco.aesop.exec_show_users.class</class>
		</action>
	</cmd>

interrupt-timeout

<!ELEMENT interrupt-timeout (#PCDATA)>

The interrupt-timeout element overrides the interrupt-timeout for this action. The parsed character data evaluates to an integer specifying the duration (in minutes) of the interrupt-timeout.

The following example is very similar to the class: Example, except for the interrupt-timeout element that sets interrupt-timeout to 10 minutes.

	<cmd>
		<pattern type="id">show</pattern>
		<help>Show running system information</help>
		<param>
			<pattern type="id">users</pattern>
			<help>Display user information</help>
		</param>
		<action>
			<class>com.cisco.aesop.exec_show_users.class</class>
			<interrupt-timeout>10</interrupt-timeout>d>
		</action>
	</cmd>

Type Regex

In the pattern tag, type= `regex' defines the contents as being a regular expression conforming to the
Perl 5 regex standard. See http://perldoc.perl.org/perlre.html for Perl 5 regex documentation.

Regex definition examples:

Example 1: A 1 or 2 digit number from 0 to 99.

<pattern type='regex'>[0-9][0-9]?</pattern>

Example 2: An alphanumeric string.1

<pattern type='regex'>[a-zA-Z0-9]*</pattern>

Example 3: An HTTP URL.

<pattern type='regex'>http://[-*.+:@?=a-zA-Z0-9/_]*</pattern>

CLI Plug-in Action APIs

CLI plug-in action scripts or classes, supported by the distribution service, are written as C classes, Java classes, and Bash shell scripts. The API of the scripts/classes is provided by the eval( ) method (for Java), or the eval( ) function (for C).

After the user enters a CLI command, a CLI plug-in action corresponding to that particular command is invoked. The CLI plug-in action interacts with the application. For further details of the necessary CLI plug-in actions, application, and DTD, see the "CLI Plug-in Applications" section.

The CLI plug-in action API is implemented by using the eval( ) method or function. Compile the API calls into the appropriate C libraries or Java classes.

The required APIs for the action class, in Java, C, or Shell script, are described below:

Java

The action class must implement the eval( ) method.

Compile Java action classes into files with a name format of <action_name>.class. The class can be in a namespace hierarchy; for example, com.xyz.myclass.class. The hierarchical class name must be defined in the XML definition for the CLI plug-in: see the class element of the "Elements and Attributes" section.

C

The action class must implement the eval( ) function.

Compile C action classes into a shared library with the name <action_name>.so.

Shell script

Shell scripts are directly executed using a C system call.

Since a shell script can only return an integer value indicating its exit status, there is no support for a shell script to pass back messages displayed on the CLI console.

The APIs use the following terms:

grammar: space delimited string that specifies the syntax of the CLI command. For example, "show time".

tokens: space delimited string that specifies the actual CLI command typed by the user. For example, "show tim", "sh time" or "sho ti".

return status: string that contains an integer specifying the CLI execution return code. 0 indicates success, non-zero indicates failure

return display: string that is displayed on the CLI console to the user who types in the CLI command

The eval and evalError action APIs are shown below for Java, C, and Bash.

eval: CLI plug-in Action API

evalError: CLI plug-in Action API


Note The grammar[ ] parameter may contain a regular expression (regex). Cisco AXP uses the Perl5 regex. For further information, see the Perl documentation at: http://perldoc.perl.org/perlre.html.


eval: CLI plug-in Action API

Java

public static String[] eval(String tokens[], String grammar[]) 

Invokes a CLI command.

The example Java code MyTime.java, includes a call to the eval( ) method. It is similar to the Java code shown in the CLI plug-in of Figure 15.

Parameters:

tokens[] - the space delimited string of tokens entered by the CLI user, 
split into an array, e.g. "sho tim" is {"sho", "tim"}

grammar[] - the space delimited string of grammar matching the tokens, 
split into an array. This grammar list is defined in the custom CLI 
definition, e.g. "show time" is {"show", "time"}

Returns:

String[] - a String array containing 2 Strings. The first String is the 
return status: "0" - succeed, non-zero - failed. For config CLIs, the 
failed return status is not saved. The second String is the return 
display. The rest of the list is ignored. For example, {"0", "Tue, 07 Aug 
2007 16:20:36"}

Example:

eval({"sho", "tim"}, {"show", "time"});
  returns the following:
  {"0", "Tue, 07 Aug 2007 16:20:36"}


C

void eval(char* tokens[], int tokens_size, char* grammar[], int 
grammar_size, char** ret_status, int* ret_status_size, char** 
ret_display, int* ret_display_size);

Invoke a CLI command.

Parameters:

tokens[] - the space delimited string of tokens entered by the CLI user, 
split into an array. For example, "sho tim" is represented as {"sho", 
"tim"}

tokens_size - length of the tokens[] array. For example, 2 (for the above 
tokens[] array.

grammar[] - the space delimited string of grammar matching the tokens, 
split into an array. This grammar list is defined in the custom CLI 
definition. For example, "show time" is represented as {"show", "time"}

grammar_size - length of the grammar[] array. For example, 2 (for the 
above grammar[] array.

ret_status - string of return status: "0" - succeed, non-zero - failed. 
For config CLIs, the failed return status is not saved.

ret_status_size - size of the ret_status string

ret_display - string of the CLI console display. For example, "Tue, 07 
Aug 2007 16:20:36"

ret_display_size - size of the ret_display string

Returns:

N/A - the parameter ret_status and ret_display (see above) provides the 
return values

Example:

my_time.c

#include ...

void eval(char* tokens[], int tokens_size, char* grammar[], int 
grammar_size, char** ret_status, int* ret_status_size, char** 
ret_display, int* ret_display_size){
...
}
...
eval({"sho", "tim"}, 2, {"show", "time"}, 2, "0", 1, "Tue, 07 Aug 2007 
16:20:36", 25);

Returns: (in parameters ret_status and ret_display)

ret_status = "0"
ret_status_size = "1"
ret_display = "Tue, 07 Aug 2007"
ret_display_size = 25

Bash

my_time.sh $1 $2

The bash shell action is invoked differently than C and Java. Instead of invoking a function inside the shell script, the script itself is invoked, passing the tokens and grammar as the arguments. Therefore, this signature applies to invoking the shell script itself.

Parameters:

$1 - CLI token list enclosed with quotes ("), CLI params are delimited by 
a space ( )

$2 - CLI grammar list  enclosed with quotes ("), CLI params are delimited 
by a space ( )

Returns:

An integer value indicating whether the command succeeded.
  0 - succeed
  Non-zero - failed
For config CLIs, the failed return status is not saved. Since a shell 
script can only return an integer value indicating its exit status, there 
is no support for a shell script to pass back any message for the CLI 
console to display.

Example:

Example script

my_time.sh

#!/bin/bash
# inside the shell script my_time.sh
...
tokens=$1
grammar=$2

# Do something with ${tokens} and ${grammar}
...

exit 0


Example script call


my_time.sh "sho tim" "show time"
returns the following:
0 

evalError: CLI plug-in Action API

Java

public static void evalError() 

Optional interrupt handler that handles interrupts during action invocation. Called in a separate thread spawned by the CLI Distribution Listener.

Parameters:

None

Returns:

None

Example:

public static void evalError() {
..
}

C

void eval_error()

Optional interrupt handler that handles interrupts during action invocation. Invoked by a signal raised from the CLI Distribution Listener main thread to the worker thread that invoked eval( ).

Parameters:

None

Returns:

None

Example:

void eval_error( ){
...
}

Supporting the no Prefix

Consider the following syntax:

>set timeout [0-9][0-9]?

The command may be prefixed with no, for example:

>no set timeout 10 

The no prefix is automatically supported for all configuration CLI's and is appended in front of the CLI tokens in the tokens array.

In the following example, the CLI plug-in action receives the items shown in these Grammar and Tokens arrays:

Grammar:

set timeout [0-9][0-9]? 

Tokens:

no set timeout 10 

CLI Plug-in Distribution Listener APIs

An application starts the CLI plug-in distribution service by calling the CLI API's plug-in distribution listener to start within the application's main program.

Starting the distribution listener allows the CLI actions to be invoked within the same program space as the main program.

The CLI plug-in distribution listener can be started in a Java, C or shell script. Depending on the language being used, the code invokes one of the following APIs in its main program.

The following Java code snippet shows the call to the startCLIDistributionVMThread( ) method.

Java
package com.cisco.aesop.apphosting.cli_distribution.CLIDistributionVM;

public static void startCLIDistributionVMThread(String appName);
  Starts the CLI Plugin Distribution Service that is non-blocking. 

Parameters:
  appName—Name of the application/virtual instance; this name must match 
the name that is used for the packaging process.

Returns:
  n/a

Example:
  CLIDistributionVM.startCLIDistributionVMThread("myAppFoo");

make/compile-time dependency:
  cli_distribution_vm.jar

run-time dependency:
  cli_distribution_vm.jar
  localsocket.jar
  /cli_comm—path to the CLI actions

The following C code snippet shows the call to the start_cli_distribution_vm_thread( ) function.

C
cli_distribution_vm.h

int start_cli_distribution_vm_thread(char* app_name);
  Starts the CLI Plugin Distribution Service that is non-blocking. 

Parameters:
  app_name—name of the application/virtual instance; this name must match 
the name that is used for the packaging process.

Returns:
  rc—return code for starting the listener
  0—succeed
  1—failed

Example:
  int rc = start_cli_distribution_vm_thread("my_app_bar");

make/compile-time dependency:
  cli_distribution_vm.h
  libcli_distribution_vm.so

run-time dependency:
  libcli_distribution_vm.so
  liblocal_socket.so

The following shell script snippet shows the call to cli_distribution_vm.

Shell Script
/bin/cli_distribution_vm $1

Parameters:
  $1—Name of the application/virtual instance, this name must match the 
name that is used for the packaging process.

Returns:
  n/a

Example:
  cli_distribution_vm my_app_bar &

CLI Plug-in Errors

Action classes communicate the return status of a command to the Cisco AXP server. The return status informs the server if the command succeeded or failed at execution. Action classes use a return string to communicate messages that must be displayed by the console to the user.

The return string is only supported in C and Java action classes.

The return status is supported by C action classes, Java action classes, and shell scripts.

Error messages are displayed on the CLI console when any of the following conditions are true:

A CLI plug-in action returns a non-zero return status code.

The Cisco AXP CLI server, CLI plug-in distribution service, or CLI plug-in actions fail to communicate with each other.

A CLI plug-in action invocation times out.

A header in the error message indicates that the message is displayed by the CLI plug-in service.

Interrupting Action Invocation

The user of a CLI plug-in can interrupt action invocation by pressing Ctrl-C.

You have the option to implement an interrupt handler to handle the Ctrl-C interrupt for action classes. The interrupt handler is only available for C, and Java. See the "evalError: CLI plug-in Action API" section. The interrupt handler is action-specific—the handler only applies to a particular action class.

In C, the interrupt handler is invoked as the same thread that has invoked the action. Raise a signal in the CLI Distribution Listener's main thread to the action invocation worker thread.

In Java, the interrupt handler is invoked as a separate thread.

An action without an interrupt handler is dealt with by the CLI Distribution Listener. The listener uses a system call to stop the thread that is executing the eval( ) function.

The interrupt handler may become stuck. A rescue timer monitors the invocation of the interrupt handling, with a default value of 5 minutes. To change the timer value, change the interrupt-timeout in the XML definition file. The definition file is explained in the "Elements and Attributes" section. If the rescue timer detects a timeout, interrupt handling is regarded as having failed. If interrupt handling fails, the CLI Distribution Listener handles the interrupt.

Table 108 describes the different scenarios for interrupt handling.

Table 108 Interrupt Handling: Scenarios 

Case
Action Contains Implementation of Interrupt Handler?
Interrupt Handler Returns from eval() Calls Immediately?
<interrupt-timeout> Element Defined as x Minutes?
Internal Interrupt Handling Description
Actions Experienced by the User

1

Yes

Yes

Yes

CLI invocation interrupted by eval_error.

CLI prompt returns, new CLI plug-in can be processed immediately.

2

Yes

Yes

No

CLI invocation interrupted by eval_error.

CLI prompt returns, new CLI plug-in can be processed immediately.

3

Yes

No

Yes

CLI invocation interrupted by distribution listener after x minutes.

CLI prompt returns, new CLI plug-in can not be processed until after x minutes.

4

Yes

No

No

CLI invocation interrupted by distribution listener after 5 minutes.

CLI prompt returns, and a new CLI plug-in can not be processed until after 5 minutes.

5

No

Yes

Yes

Case not possible.

Case not possible.

6

No

Yes

No

Case not possible.

Case not possible.

7

No

No

Yes

CLI invocation interrupted by CLI Distribution Listener immediately.

CLI prompt returns, and a new CLI plug-in can be processed immediately.

8

No

No

No

CLI invocation interrupted by CLI Distribution Listener immediately.

CLI prompt returns, and a new CLI plug-in can be processed immediately.


Simultaneous CLI plug-in Invocation

Multiple CLI sessions can be opened by a user. However, simultaneous CLI plug-in invocation to the same CLI Distribution Listener is not supported. When the CLI Distribution Listener is processing one CLI plug-in (that is, a CLI plug-in action is being invoked and has not yet returned), the listener blocks any new CLI plug-in request. Users see a message displayed on the CLI console saying that the CLI plug-in request is blocked, try again later.

CLI Plug-in Application: Example

The development of simple CLI plug-in applications is shown in the following sections.

Health Status

Package Name

Show Time Application: Example

Health Status

We recommend that the health status is coded in an application for the show state cli command to show your application's health status.

If health status is not coded in an application, when the show state command is issued, the reported health status of an application is shown as dashes "---".

show state command (where the Application Health Status is not Coded): Example

my-javalin> app-service helloworld
my-javalin(exec-appservice)> show state

APPLICATION STATE HEALTH

helloworld online ---

Package Name

You must determine the package name for your application. The same package name must be used in the following three places:

1. Package name assigned to the VM topic in the cli_plugin.config file

2. Package name assigned as an argument when the application calls the API startCLIDistributionVMThread( )

3. Package name assigned to the **name argument of the packaging tool

Show Time Application: Example

A custom command is defined by an XML definition file and an action script. You can create code for the custom command, package it with your application, and then import it into Cisco AXP.

As an example, consider an application which has to respond to a user request to display the time using the command show time. (The user request is shown as step 3 in Figure 16.)

To develop the "show time" example, perform the following steps.


Step 1 Create a directory: mkdir /source/showtimeapp.

Step 2 Create an XML file MyTime.xml and save the file to directory /source/showtimeapp. See the "XML Script: Example" section.

Step 3 Create action class MyTime.java. See the "Action Class: Example" section.

Step 4 Create an application (listener). See the "Starting a Listener from the Application: Example" section.

Step 5 Build and test. See the "Building and Testing: Example" section.

Step 6 Prepackage the CLI plug-in application. See the "Prepackaging the CLI Plug-in: Example" section.


Figure 16 describes the sequence of events when the showtime CLI plug-in application runs on the Cisco AXP CLI server.

Figure 16 CLI Plug-in Application: Example

XML Script: Example

Use the XML DTD to write an XML definition file. For further information on XML DTD definitions, see the "XML DTD File" section.

The following code script, MyTime.xml show time.

<?xml version='1.1' encoding='UTF-8' ?>
<!DOCTYPE cli_grammar SYSTEM "cli_grammar.dtd" >

<cli_grammar>
  <mode>
    <pattern type="id">exec</pattern>
    <cmd>
      <pattern type="id">show</pattern>
        <help>show time</help>
      <param>
        <pattern type="id">time</pattern>
        <help>show current time</help>
      </param>
      <action>
        <class>MyTime.class</class>
      </action>
     </cmd>
  </mode>
</cli_grammar>

When the user enters command show time, Java action class MyTime.class is called.

Action Class: Example

MyTime.java returns the date and time. The eval() method is the API that accepts the user's CLI command and returns the current date and time. For a further explanation of the eval( ) method, see the "CLI Plug-in Action APIs" section.

/*MyTime.java is a simple CLI Action class that returns the application return code and
*the current date/time. If it fails an application return code of 1 is returned along
*with the exception message. The static main program can be invoked to easily test the
*program independently
*/
import java.util.Date;
import java.text.SimpleDateFormat;

/**
* Returns the current time of the day
*/

public class MyTime{
	public static String[] eval(String[] tokens, String[] grammar){
		String[] retArray = new String[2];
		try{
			if(tokens.length == 2 && grammar[0].tolower().equals("show") &&
			grammar[1].tolower().equals("time")){
				Date curTime = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss");
				retArray[0]="0";
				retArray[1]=sdf.format(curTime);
				}
			else{
				retArray[0]="1";
				retArray[1]="Unknown command";
			}
		}
		catch(Exception e){
			retArray[0]="1";
			retArray[1]=e.getMessage();
		}
		return retArray;
	}

	public static void main(String[] args){
		String[] tokens = {"show","time"};
		String[] grammer = {"show","time"};
		String[] message = eval(tokens,grammer);
		System.out.println("Exit code: " + message[0] + "  Result:" + message[1]);
	}
}

The XML script MyTime.xml defines the show time command. See the "XML Script: Example" section.

After compiling and testing the above action class (MyTime.class), store it in file showtime.jar so that it can be easily accessed later. Place the jar file in the /source/showtimeapp directory:
jar -cvf showtime.jar MyTime.class

When the user enters command show time, this action class MyTime.class processes the command. See the "Action Class: Example" section.

For the class MyTime.class to be called, a listener must be started in your application. See the "Starting a Listener from the Application: Example" section.

Starting a Listener from the Application: Example

Start an application listener using the thread startCLIDistributionVMThread. For example, the following command is used within the application MyAppMgr.

CLIDistributionVM.startCLIDistributionVMThread("showtime");

MyAppMgr gives the health status of the application, and activates a VM thread which listens for the defined show time command. When the user enters the show time command, the application calls the MyTime class.


/*
* Third party application that reports its health status, starts up the CLI distribution
* thread, and then waits.
*/
import com.cisco.aesop.apphosting.cli_distribution.CLIDistributionVM;
import java.io.*;
import java.lang.*;

public class MyAppMgr{
/**
*Displays and writes passed in message
*@param msg: message to be displayed and logged.
*@param pw: PrintWriter object
*@return nothing
*
*/
	public void printMessage(String msg, PrintWriter pw){
		System.out.println(msg);
		if(pw != null){
			pw.println(msg);
			pw.flush();
		}
	}
	/**
	*Sends the health status.  Logs exception.
	*@param name: application package name
	*@param status: health status
	*@param pw: PrintWriter object
	*@return nothing
	*
	*/

	public void sendStatus(String name, String status, PrintWriter pw){
		try{
			Runtime rt = Runtime.getRuntime();
			rt.exec("/bin/app_status_notifier " + name + " " + status);
		}
		catch(Exception e){
			printMessage("Send of status failed.  Exception " + e.getMessage(),pw); 
		}
	}

//code for testing application
	public static void main(String[] args){
	MyAppMgr mgr = new MyAppMgr();
	PrintWriter pw = null;
	try{
		pw = new PrintWriter(new FileOutputStream(new File("/var/log/showtime.log"))); 
		mgr.sendStatus("showtime","INITIALIZING",pw); 
		mgr.printMessage("Starting VM Thread",pw);
// The following line starts the listener
		CLIDistributionVM.startCLIDistributionVMThread("showtime");
		Object obj = new Object();
		synchronized(obj){
			mgr.sendStatus("showtime","ALIVE",pw);
			mgr.printMessage("Going into wait mode",pw);
			pw.flush();
			obj.wait();
		}
	}
	catch(Exception e){
		mgr.printMessage("Exception " + e.getMessage(),pw);
	}
	finally{
		mgr.printMessage("Exiting MyAppMgr program",pw);
		mgr.sendStatus("showtime","DOWN",pw);
		if(pw != null){
			pw.close();
		}
	}
	} //end main
} //end class

Building and Testing: Example

Build

[bash]# javac -classpath cli_distribution_vm.jar MyAppMgr.java

Add this class to file showtime.jar, which allows for easy access later.

jar -uvf showtime.jar MyAppMgr.class 

Test

For testing, you need access to the following Linux library: liblocal_socket.so.

Copy showtime.jar to directory /source/showtimeapp.

The java command below tests application MyAppMgr. File liblocal_socket.so and jar files are in directory "lib" —one level below the current directory.


Note You must be user "root" to perform this test in your development environment.



Note Provided your application (MyTime) is packaged with a dependency on the CLI plug-in package, then showtime.jar is the only one to be packaged. This is because the file liblocal_socket.so and other jar files are in the guest OS (virtual instance).


[bash]# java -Djava.library.path=lib/ -cp 
lib/cli_distribution_vm.jar:lib/localsocket.jar:lib/showtime.jar MyAppMgr

Output:

Starting VM Thread
Going into wait mode
CLI_PLUGIN:CLIDistributionVM.receiveIPCMessages: server socket opened successfully

Create a build directory

Create a directory to hold prepackaged files to be packaged and installed onto Cisco AXP:

mkdir /source/showtimeapp/build

Prepackaging the CLI Plug-in: Example

The following example of prepackaging a CLI plug-in application follows the steps in the "Prepackaging the CLI Plug-in" section.


Step 1 Copy the action file MyTime.class into directory actions/.

Step 2 Copy CLI plug-in definition file MyTime.xml into directory definitions/.

Step 3 Edit the configuration file cli_plugin.config.

file=MyTime.xml

javapath=/usr/bin/java/bin

vm=showtime

proj_src=/source/showtimeapp/build

You have the option of whether to change the proj_src argument or not. See proj_src in Table 107.

Step 4 Run the CLI plug-in SDK packaging tool to package the definitions and actions.

python cli-plugin.py

For further information, see step 4 of the "Prepackaging the CLI Plug-in" section.

Next, move the tar file to the source directory, see the "Moving the tar File: Example" section.

Prepackaging is complete.