AXP(Application eXtension Platform)/CLI Plug-in

バージョン 5

    AXP(Application eXtension Platform)へ戻る

     

    CLI プラグイン

    Cisco AXP CLI プラグインを使用すると、アプリケーション固有のコマンドを作成して、Cisco AXP CLI 上で使用可能なコマンドを追加できます。

     

    CLI プラグイン API 用のファイル

    Cisco AXP SDK には、CLI プラグインコマンドを作成するために必要なライブラリおよびモジュールが含まれます。以下に、SDK でサポートされる言語および関連ライブラリ/ モジュールを示します。

    言語ライブラリ/ モジュール/ ヘッダー ファイル
    C/C++{SDK}/include/cli_distribution_vm.h {SDK}/lib/libcli_distribution_vm.so
    Java{SDK}/jar/cli_distribution_vm.jar

     

    show time コマンドの作成

    これから作成するshow time CLIプラグインのシーケンスを示します。

    ※ ここでは、AXP SDKのインストールパスを、/opt/AXP/sdk としています。

     

    パッケージフォルダの作成

    showtimeパッケージフォルダを作成します。

    [~]# cd /opt/AXP/apps
    [apps]# mkdir showtime
    [apps]# cd showtime

    [showtime]# mkdir -p build/bin
    [showtime]# mkdir -p build/third_party_rpms_repository
    [showtime]# mkdir -p src
    [showtime]# mkdir -p package
    [showtime]# cp -r /opt/AXP/sdk/tools/custom_cli .

    [showtime]# cp ~/jre-6u21-linux-i586.rpm build/third_party_rpms_repository

    srcフォルダは、これから作成するJavaソースの作業フォルダになります。

    sdkからコピーしたcustom_cliは、CLIプラグインのプレパッケージを作成するためのフォルダです。

    また、今回の紹介ではjavaを使うため、JREのRPMをインストールします。

    build/bin には、コンソールでアクセスできるよう、login.sh と post-install.sh を配置します。詳細は、 コンソールアクセス権の取得を参照してください。

     

    CLIプラグインアクションの作成(Javaの場合)

    時刻表示を行うプログラム(CLIプラグインアクション)を作成します。eval メソッドを必ず追加する必要があります。 eval メソッドは、以下の形式です。

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

    tokens[] には、ユーザがCLIで入力した文字列が設定されます。たとえば、ユーザが、CLIで「sh tim」と入力した場合は、{"sh","tim"}のようにです。

    grammar[] には、カスタムCLIで定義した文法が設定されます。たとえば、「show time」と設定していた場合は、{"show","time"}のようにです。

    1. プログラム MyTime.javaを作成します。
      [showtime]# cd src
      [src]# cat <<EOT>MyTime.java
      import java.util.Date;
      import java.text.SimpleDateFormat;

      public class MyTime {
          public static String[] eval(String[] tokens, String[] grammer) {
              String[] retArray = new String[2];
              try {
                  if (tokens.length==2 &&
                      grammer[0].toLowerCase().equals("show") &&
                      grammer[1].toLowerCase().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]);
          }
      }
      EOT
      [src]#
    2. コンパイルします。
      [src]# javac MyTime.java

     

    CLIプラグイン定義の作成

    ユーザが入力するコマンドの構文を定義します。(CLIプラグイン定義)

    [src]# cd ../custom_cli/definitions
    [definitions]# cat <<EOT>MyTime.xml
    <?xml version='1.0' 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>
    EOT

    ここでは、show timeというコマンドの定義、helpメッセージ、コマンド入力時に実行するアクションコマンドMyTime.classを定義しています。

     

    CLIプラグインのプレパッケージ

    ここまでの作業で、以下のファイル,フォルダが作成されています。

    showtime/build
            /package
            /src
                MyTime.java, MyTime.class
            /custom_cli (コピーしたファイルは省略)
                /definitions
                    MyTime.xml

    cli-plugin.py ツールを使い、プレパッケージを作成します。

    1. actionsにアクションファイルをコピーします。
      [showtime]# cp src/MyTime.class custom_cli/actions
    2. コンフィグレーションファイルを編集します。
      [showtime]# vi custom_cli/cli_plugin.config


      file=MyTime.xml
      javapath=/usr/bin
      vm=showtime
      proj_src=/opt/AXP/apps/showtime/build
    3. CLI プラグイン SDKツールを実行して、定義およびアクションをパッケージ化します。
      [showtime]# cd custom_cli
      [custom_cli]# python cli_plugin.py
      cli_plugin.py ran successfully, please check the packages at output/

      Also, the package has been bundled into the project source directory at /opt/AXP/apps/showtime/build
      [custom_cli]#

    この時点で、showtime/buildフォルダに、cli_commフォルダが作成されCLIプラグインのファイル群がコピーされます。

    また、custom_cli/output には、showtime.tar が生成されます。この中は、build フォルダと同じ内容です。

     

    CLI プラグイン ディストリビューション リスナーの作成

    1. リスナー(CLI プラグイン ディストリビューション リスナー)を作成します。この例では、リスナーの機能のみ提供するプログラムになっていますが、実際は、ユーザが作成するアプリケーションに組み込みます。
      [src]# cat <<EOT>MyAppMgr.java
      import com.cisco.aesop.apphosting.cli_distribution.CLIDistributionVM;
      import java.io.*;

      public class MyAppMgr{
          public void printMessage(String msg, PrintWriter pw) {
              System.out.println(msg);
              if (pw!=null) {
                  pw.println(msg);
                  pw.flush();
              }
          }

          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);
              }
          }

          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);
                  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();
                  }
              }
          }
      }
      EOT
    2. コンパイルします。
      [src]# javac -classpath /opt/AXP/sdk/jar/cli_distribution_vm.jar MyAppMgr.java
    3. リスナーをbuildにコピーします。
      [src]# cp MyAppMgr.class ../build/cli_comm/.

     

    showtimeパッケージの作成

    1. CLIプラグインの利用には、axp-cli-plugin との依存関係をdepsで定義する必要があります。
      [showtime]# pkg_info.sh /opt/AXP/sdk/pkg/axp-cli-plugin.vmw.1.1.1.pkg
      Subsystem ID: b4b0ee92-cf8e-472b-8434-e8e7412ec71a
      Name: cli_plugin
      Version: 1.1.1
    2. パッケージを作成します。
      [showtime]# uuidgen
      05383fc0-1405-47d5-a7cb-acd3f0bc1d3e
      [showtime]# pkg_build.sh \
        --project-dir '/opt/AXP/apps/showtime/package' \
        --auth-bundle '/opt/AXP/keys/auth_bundle.sig' \
        --private-key '/opt/AXP/keys/private.key' \
        --name 'showtime' --version '1.0' --description 'showtime cli app' \
        --uuid '05383fc0-1405-47d5-a7cb-acd3f0bc1d3e' \
        --source-dir '/opt/AXP/apps/showtime/build' \
        --deps 'b4b0ee92-cf8e-472b-8434-e8e7412ec71a,all' \
        --disk-limit '100M' --memory-limit '128M' --cpu-limit '500'
      ※ CLI Plugin に依存するため、depsに CLI Pluginパッケージのuuidを設定しています。
    3. ftpフォルダへコピーします。
      [showtime]# cp package/pkg/showtime* /var/ftp

     

    showtimeのインストールと動作確認

    1. AXPにshowtimeパッケージをインストールします。
      AXP# software install add url ftp://192.168.71.36/showtime.1.0.pkg
    2. 再起動が終わったら、コンソールアクセスするように設定します。参照(コンソールアクセス権の取得)
    3. コンソールに接続し、リスナーを起動します。
      AXP# app-service showtime
      AXP(exec-showtime)# connect console
      bash-3.2# cd /cli_comm/
      bash-3.2# java -cp .:/cli_comm:/usr/lib/java/cli_distribution_vm.jar MyAppMgr
      Starting VM Thread
      Going into wait mode
    4. 別のターミナルからAXPへSSHで接続し、リスナーが起動していることを確認します。
      sysadmin@AXP's password: 

      AXP#
      AXP# app-service showtime
      AXP(exec-showtime)# show process
      USER      PID %CPU %MEM    VSZ  RSS TTY      STAT START  TIME COMMAND
      root        1  0.0  0.4  1968  608 ?        S    14:09  0:00 init [3]
      ~省略~
      401      24337  0.0  0.7  2484  1020 pts/2    S+  15:34  0:00 java -cp /cli_comm:/usr/lib/java/cli_distribution_vm.jar MyAppMgr
      AXP(exec-showtime)#
    5. ヘルプ表示を確認します。
      AXP(exec-showtime)# show ?
      ~省略~
        time        show current time
    6. show timeを実行します。
      AXP(exec-showtime)# show time
      Mon, 30 Mar 2009 15:58:51

      AXP(exec-showtime)#

     

    Cの場合

    Cの場合は、シェアードライブラリを作成する必要があります。シェアードライブラリには、eval()関数を必ず作成する必要があります。

    eval関数は、以下のように定義します。

     

    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);

     

    tokens[] には、ユーザがCLIで入力した文字列が設定されます。たとえば、ユーザが、CLIで「sh tim」と入力した場合は、{"sh","tim"}のようにです。

    tokens_size には、tokensの配列数が設定されます。

    grammar[] には、カスタムCLIで定義した文法が設定されます。たとえば、「show time」と設定していた場合は、{"show","time"}のようにです。

    grammar_size には、grammarの配列数が設定されます。

    ret_status には、実行結果の状態を設定します。成功した場合は0で、失敗した場合は0以外となります。

    ret_stauts_size には、ret_statusの文字列の長さを設定します。

    ret_display には、実行結果(コンソールに表示したい内容)を設定します。

    ret_display_size には、ret_displayの文字列の長さを設定します。

     

    1. showtime.c を作成します。

      [src]# cat <<EOT>showtime.c

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <strings.h>
      #include <errno.h>
      #include <time.h>

      const char *LOG="/var/log/showtime.log";

      void logRequest (char* level, char* msg) {

              if(level == NULL || msg == NULL){
                      return;
              }

              FILE *fp;
              if(fp=fopen(LOG,"a")){
                      time_t t;
                      struct tm *tm;
                      time(&t);
                      tm = localtime(&t);
                      fprintf(fp,"%s %s %s\n",asctime(tm),level,msg);
                      fclose(fp);
              }
      }

      int engine(char* tokens[],int tokens_size,char* grammar[],int grammar_size,char** ret_display){
              int err = 0;
              int ret_val=1;
              char* cmdChk=NULL;

              if(tokens_size >=2){
                      int i;
                      for (i=0;i<grammar_size;i++) {
                              if (strncmp(tokens[i],grammar[i],strlen(tokens[i]))!=0) err=1;
                      }
                      if (!err) {
                              time_t t;
                              struct tm *tm;
                              time(&t);
                              tm = localtime(&t);
                              *ret_display = malloc(100);
                              sprintf(*ret_display,"%s",asctime(tm));
                              ret_val = 0;
                      }
              }else{
                      logRequest("Error","Invalid command - too short");
              }

              return ret_val;
      }

      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){

              int ret_val=engine(tokens,tokens_size,grammar,grammar_size,ret_display);
              *ret_status=(char*)malloc(5);
              sprintf(*ret_status,"%d",ret_val);
              *ret_status_size=strlen(*ret_status);
              if(*ret_display != NULL){
                      *ret_display_size=strlen(*ret_display);
              }
      }

      int main(int argc, char *argv[]){
              //Test Commands
              char *tokens[10];
              char *grammer[]={"show","time"};
              int tokens_size=0;

              char *ret_status=NULL;
              int ret_status_size=0;
              char *ret_display=NULL;
              int ret_display_size=0;

              int i;
              for (i=1;i<argc;i++) {
                      tokens[i-1]=argv[i];
                      tokens_size++;
              }
              eval(tokens,tokens_size,grammer,2,&ret_status,&ret_status_size,&ret_display,&ret_display_size);
              printf("Got returns values %s %d %s %d",ret_status,ret_status_size,ret_display,ret_display_size);
              if (ret_display) free(ret_display);
              if (ret_status) free(ret_status);

              return 0;
      }
      EOT

    2. コンパイルし、シェアードライブラリを作成します。
      [src]# gcc -c showtime.c
      [src]# gcc -shared -o libshowtime.so showtime.o
    3. シェアードライブラリをcustom_cli/actionsにコピーします。  
      [src]# cp libshowtime.so ../custom_cli/actions/.
    4. custom_cli/definitions/MyTime.xmlを作成します。
      <?xml version='1.0' 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>libshowtime.so</class>
            </action>
          </cmd>
        </mode>
      </cli_grammar>
      EOT
    5. プレパッケージ、パッケージの方法は同じです。
    6. コンソールに接続し、リスナーを起動します。
      [workstation]$ slogin sysadmin@AXP
      sysadmin@AXP's password:

      bash-3.2# cd /cli_comm/
      bash-3.2# /bin/cli_distribution_vm showtime

     

    シェルスクリプトの場合

    シェルスクリプトの場合は、以下のようになります。

     

    custom_cli/actions/my_time.sh

    #!/bin/bash
    tokens=$1
    grammar=$2
    echo $tokens
    echo $grammar
    exit 0

     

    custom_cli/definitions/MyTime.xml

    <?xml version='1.0' 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>my_time.sh</class>
          </action>
        </cmd>
      </mode>
    </cli_grammar>
    EOT

    プレパッケージ、パッケージの方法は同じです。

    コンソールに接続し、リスナーを起動します。

    [workstation]$ slogin sysadmin@AXP
    sysadmin@AXP's password:

    bash-3.2# cd /cli_comm/
    bash-3.2# /bin/cli_distribution_vm showtime