You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by pl...@apache.org on 2016/06/01 01:45:47 UTC

directory-kerby git commit: DIRKRB-574 Implement a concurrent test to benchmark throughput and latency of kerby KDC. Contributed by Qing.

Repository: directory-kerby
Updated Branches:
  refs/heads/trunk f751d3906 -> 741473254


DIRKRB-574 Implement a concurrent test to benchmark throughput and latency of kerby KDC. Contributed by Qing.


Project: http://git-wip-us.apache.org/repos/asf/directory-kerby/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerby/commit/74147325
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerby/tree/74147325
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerby/diff/74147325

Branch: refs/heads/trunk
Commit: 741473254f5891a748aa2942cefe25e3f3e70323
Parents: f751d39
Author: plusplusjiajia <ji...@intel.com>
Authored: Wed Jun 1 09:51:16 2016 +0800
Committer: plusplusjiajia <ji...@intel.com>
Committed: Wed Jun 1 09:51:16 2016 +0800

----------------------------------------------------------------------
 .../identitybackend/JsonIdentityBackend.java    |   1 +
 kerby-dist/tool-dist/bin/kinitConcurrent.cmd    |  33 ++
 kerby-dist/tool-dist/bin/kinitConcurrent.sh     |  33 ++
 .../kerby/kerberos/kerb/admin/KadminOption.java |   1 +
 .../kerby/kerberos/kerb/admin/LocalKadmin.java  |   2 +
 .../kerberos/kerb/admin/LocalKadminImpl.java    |   8 +
 .../tool/kinit/KinitToolWithConcurrence.java    | 326 +++++++++++++++++++
 .../kerby/kerberos/tool/kadmin/KadminTool.java  |   6 +
 .../kadmin/command/AddPrincipalsCommand.java    | 112 +++++++
 9 files changed, 522 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java
----------------------------------------------------------------------
diff --git a/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java b/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java
index ad61967..3908cc5 100644
--- a/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java
+++ b/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java
@@ -244,6 +244,7 @@ public class JsonIdentityBackend extends AbstractIdentityBackend {
      */
     @Override
     protected Iterable<String> doGetIdentities() throws KrbException {
+        load();
         List<String> principals = new ArrayList<>(identities.keySet());
         Collections.sort(principals);
 

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-dist/tool-dist/bin/kinitConcurrent.cmd
----------------------------------------------------------------------
diff --git a/kerby-dist/tool-dist/bin/kinitConcurrent.cmd b/kerby-dist/tool-dist/bin/kinitConcurrent.cmd
new file mode 100644
index 0000000..359e370
--- /dev/null
+++ b/kerby-dist/tool-dist/bin/kinitConcurrent.cmd
@@ -0,0 +1,33 @@
+@echo off
+@rem  Licensed to the Apache Software Foundation (ASF) under one
+@rem  or more contributor license agreements.  See the NOTICE file
+@rem  distributed with this work for additional information
+@rem  regarding copyright ownership.  The ASF licenses this file
+@rem  to you under the Apache License, Version 2.0 (the
+@rem  "License"); you may not use this file except in compliance
+@rem  with the License.  You may obtain a copy of the License at
+@rem
+@rem    http://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem  Unless required by applicable law or agreed to in writing,
+@rem  software distributed under the License is distributed on an
+@rem  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@rem  KIND, either express or implied.  See the License for the
+@rem  specific language governing permissions and limitations
+@rem  under the License.
+@rem
+
+set DEBUG=
+set args=%*
+for %%a in (%*) do (
+  if -D == %%a (
+    set DEBUG=-Xdebug -Xrunjdwp:transport=dt_socket,address=8002,server=y,suspend=y
+    set args=%args:-D=%
+  )
+)
+
+java %DEBUG% ^
+-classpath target\lib\* ^
+-DKERBY_LOGFILE=kinit ^
+org.apache.kerby.kerberos.tool.kinit.KinitToolWithConcurrence %args%
+

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-dist/tool-dist/bin/kinitConcurrent.sh
----------------------------------------------------------------------
diff --git a/kerby-dist/tool-dist/bin/kinitConcurrent.sh b/kerby-dist/tool-dist/bin/kinitConcurrent.sh
new file mode 100644
index 0000000..7c46052
--- /dev/null
+++ b/kerby-dist/tool-dist/bin/kinitConcurrent.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+DEBUG=
+args=
+for var in $*; do
+  if [ X"$var" = X"-D" ]; then
+    DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,address=8002,server=y,suspend=y"
+  else
+    args="$args $var"
+  fi
+done
+
+java $DEBUG \
+-classpath target/lib/*:. \
+-DKERBY_LOGFILE=kinit \
+org.apache.kerby.kerberos.tool.kinit.KinitToolWithConcurrence $args
+

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
index bdab4d6..0c11fe7 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/KadminOption.java
@@ -30,6 +30,7 @@ public enum KadminOption implements KOption {
     LOCKED(new KOptionInfo("-locked", "locked", KOptionType.BOOL)),
     FORCE(new KOptionInfo("-force", "force", KOptionType.NOV)),
     KVNO(new KOptionInfo("-kvno", "initial key version number", KOptionType.INT)),
+    SIZE(new KOptionInfo("-size", "principal's numbers", KOptionType.STR)),
     PW(new KOptionInfo("-pw", "password", KOptionType.STR)),
     RANDKEY(new KOptionInfo("-randkey", "random key", KOptionType.NOV)),
     KEEPOLD(new KOptionInfo("-keepold", "keep old passowrd", KOptionType.NOV)),

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java
index 6125f0b..d8d38f1 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadmin.java
@@ -82,4 +82,6 @@ public interface LocalKadmin extends Kadmin {
      * @throws KrbException e
      */
     KrbIdentity getPrincipal(String principalName) throws KrbException;
+
+    int size() throws KrbException;
 }

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java
----------------------------------------------------------------------
diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java
index 5ba4eb8..9f0f89e 100644
--- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java
+++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/LocalKadminImpl.java
@@ -379,6 +379,14 @@ public class LocalKadminImpl implements LocalKadmin {
     }
 
     /**
+     * get size of principal
+     */
+    @Override
+    public int size() throws KrbException {
+        return this.getPrincipals().size();
+    }
+
+    /**
      * Fix principal name, making it complete.
      *
      * @param principal The principal name

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitToolWithConcurrence.java
----------------------------------------------------------------------
diff --git a/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitToolWithConcurrence.java b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitToolWithConcurrence.java
new file mode 100644
index 0000000..7427307
--- /dev/null
+++ b/kerby-tool/client-tool/src/main/java/org/apache/kerby/kerberos/tool/kinit/KinitToolWithConcurrence.java
@@ -0,0 +1,326 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.tool.kinit;
+
+import org.apache.kerby.KOption;
+import org.apache.kerby.KOptionGroup;
+import org.apache.kerby.KOptionInfo;
+import org.apache.kerby.KOptionType;
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.client.KrbClient;
+import org.apache.kerby.kerberos.kerb.client.KrbKdcOption;
+import org.apache.kerby.kerberos.kerb.client.KrbOption;
+import org.apache.kerby.kerberos.kerb.client.KrbOptionGroup;
+import org.apache.kerby.kerberos.kerb.client.PkinitOption;
+import org.apache.kerby.kerberos.kerb.client.TokenOption;
+import org.apache.kerby.util.OSUtil;
+import java.io.File;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * kinit like tool with concurrence
+ *
+ * Ref. MIT kinit command tool usage.aa
+ */
+public class KinitToolWithConcurrence {
+    /**
+     * control the number of request
+     */
+    private static int[] reList = new int[100000];
+    private static String[] prList = new String[10000];
+    private static KOptions ktOptions = new KOptions();
+    private static int thFlag = 0;
+    private static Long startTime = 0L;
+    private static Lock lock = new ReentrantLock();
+    private static int tmpTotals = 0;
+    private static final int INTERVAL = 16;
+
+    private static final String USAGE = (OSUtil.isWindows()
+            ? "Usage: bin\\kinit.cmd" : "Usage: sh bin/kinit.sh")
+            + " <-conf conf_dir> [-V] [-l lifetime] [-s start_time]\n"
+            + "\t\t[-r renewable_life] [-f | -F] [-p | -P] -n [-a | -A] [-C] [-E]\n"
+            + "\t\t[-v] [-R] [-k [-i|-t keytab_file]] [-c cachename]\n"
+            + "\t\t[-S service_name] [-T ticket_armor_cache]\n"
+            + "\t\t[-X <attribute>[=<value>]] <principal>\n\n"
+            + "\tDESCRIPTION:\n"
+            + "\t\tkinit obtains and caches an initial ticket-granting ticket for principal.\n\n"
+            + "\tOPTIONS:\n"
+            + "\t\t-V verbose\n"
+            + "\t\t-l lifetime\n"
+            + "\t\t--s start time\n"
+            + "\t\t-r renewable lifetime\n"
+            + "\t\t-f forwardable\n"
+            + "\t\t-F not forwardable\n"
+            + "\t\t-p proxiable\n"
+            + "\t\t-P not proxiable\n"
+            + "\t\t-n anonymous\n"
+            + "\t\t-a include addresses\n"
+            + "\t\t-A do not include addresses\n"
+            + "\t\t-v validate\n"
+            + "\t\t-R renew\n"
+            + "\t\t-C canonicalize\n"
+            + "\t\t-E client is enterprise principal name\n"
+            + "\t\t-k use keytab\n"
+            + "\t\t-i use default client keytab (with -k)\n"
+            + "\t\t-t filename of keytab to use\n"
+            + "\t\t-c Kerberos 5 cache name\n"
+            + "\t\t-S service\n"
+            + "\t\t-T armor credential cache\n"
+            + "\t\t-X <attribute>[=<value>]\n"
+            + "\n";
+
+
+    private static void printUsage(String error) {
+        System.err.println(error + "\n");
+        System.err.println(USAGE);
+        System.exit(-1);
+    }
+
+    private static void requestTicket(String principal,
+                                      KOptions ktOptions, int flag) throws KrbException {
+        ktOptions.add(KinitOption.CLIENT_PRINCIPAL, principal);
+
+        File confDir = null;
+        if (ktOptions.contains(KinitOption.CONF_DIR)) {
+            confDir = ktOptions.getDirOption(KinitOption.CONF_DIR);
+        }
+
+        if (ktOptions.contains(KinitOption.ANONYMOUS)) {
+            ktOptions.add(PkinitOption.USE_ANONYMOUS);
+            ktOptions.add(PkinitOption.X509_ANCHORS);
+        } else if (!ktOptions.contains(KinitOption.USE_KEYTAB)) {
+            //If not request tickets by keytab than by password.
+            ktOptions.add(KinitOption.USE_PASSWD);
+            String password = "12";
+            ktOptions.add(KinitOption.USER_PASSWD, password);
+        }
+
+        KrbClient krbClient = null;
+        try {
+            krbClient = getClient(confDir);
+        } catch (KrbException e) {
+            System.err.println("Create krbClient failed: " + e.getMessage());
+            System.exit(1);
+        }
+
+        KOptions results =  convertOptions(ktOptions);
+        try {
+            flag *= INTERVAL;
+            while (true) {
+                krbClient.requestTgt(results);
+                reList[flag] += 1;
+            }
+        } catch (KrbException e) {
+            System.err.println("Authentication failed: " + e.getMessage());
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Init the client.
+     */
+    private static KrbClient getClient(File confDir) throws KrbException {
+        KrbClient krbClient;
+
+        if (confDir != null) {
+            krbClient = new KrbClient(confDir);
+        } else {
+            krbClient = new KrbClient();
+        }
+
+        krbClient.init();
+        return krbClient;
+    }
+
+    public static void main(String[] args) throws Exception {
+        KinitOption kto;
+        String principalNumbers = null;
+        String startIndex = null;
+
+        int i = 0;
+        String opt, param, error;
+        while (i < args.length) {
+            error = null;
+
+            opt = args[i++];
+            if (opt.startsWith("-")) {
+                kto = KinitOption.fromName(opt);
+                if (kto == KinitOption.NONE) {
+                    error = "Invalid option:" + opt;
+                    System.err.println(error);
+                    break;
+                }
+            } else {
+                principalNumbers = opt;
+                kto = KinitOption.NONE;
+                // require a parameter
+                startIndex = args[i++];
+            }
+
+            if (kto != KinitOption.NONE && kto.getOptionInfo().getType() != KOptionType.NOV) {
+                // require a parameter
+                param = null;
+                if (i < args.length) {
+                    param = args[i++];
+                }
+                if (param != null) {
+                    KOptions.parseSetValue(kto.getOptionInfo(), param);
+                } else {
+                    error = "Option " + opt + " require a parameter";
+                }
+            }
+
+            if (error != null) {
+                printUsage(error);
+            }
+            if (kto != KinitOption.NONE) {
+                ktOptions.add(kto);
+            }
+        }
+
+        int threadNumbers = Integer.parseInt(principalNumbers);
+        int stIndex = Integer.parseInt(startIndex);
+
+        if (threadNumbers <= 0) {
+            printUsage("principal must be greater than zero");
+            System.exit(-1);
+        }
+
+        for (int j = 0; j < threadNumbers; j++) {
+            int tmpIndex = j + stIndex;
+            String tempName = "E" + tmpIndex + "@EXAMPLE.COM";
+            prList[j] = tempName;
+        }
+
+        for (int j = 0; j < threadNumbers; j++) {
+            Thread th = new Thread(new PreThread());
+            th.start();
+        }
+
+        // statistical
+        int[] tempDelayNumbers = new int[threadNumbers];
+        int[] delayNumbers = new int[threadNumbers];
+        startTime = System.currentTimeMillis();
+        Long timeStamp = System.currentTimeMillis();
+
+        int max = 0;
+        int min = 0;
+
+        System.out.println("Time stamp (sec),Throughput (sec),"
+                + "avgDelay (ms),maxDelay (ms),minDelay (ms)");
+
+        while (true) {
+            Thread.sleep(2000);
+            int temp = 0;
+            Long now = System.currentTimeMillis();
+
+            for (int j = 0; j < threadNumbers; j++) {
+                delayNumbers[j] = reList[j * INTERVAL] - delayNumbers[j];
+                tempDelayNumbers[j] =  reList[j * INTERVAL];
+            }
+
+            for (int j = 0; j < threadNumbers; j++) {
+                temp += reList[j * INTERVAL];
+            }
+            float res = (now - startTime) / 1000;
+
+            int totalDelay = 0;
+            for (int j = 0; j < threadNumbers; j++) {
+                if (delayNumbers[j] != 0) {
+                    if (delayNumbers[max] < delayNumbers[j]) {
+                        max = j;
+                    }
+                    if (delayNumbers[min] == 0 || delayNumbers[min] > delayNumbers[j]) {
+                        min = j;
+                    }
+                    totalDelay += (now - startTime) / delayNumbers[j];
+                }
+            }
+            if (delayNumbers[min] != 0 && delayNumbers[max] != 0) {
+                System.out.println((now - timeStamp) / 1000 + "," + (temp - tmpTotals) / res
+                        + "," + totalDelay / threadNumbers
+                        + "," + (now - startTime) / delayNumbers[min] + "," + (now - startTime) / delayNumbers[max]);
+            }
+
+            tmpTotals = temp;
+            startTime = now;
+        }
+
+    }
+
+    public static class PreThread implements Runnable {
+        @Override
+        public void run() {
+            try {
+                request();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public static void request() throws Exception {
+        int tempFlag = 0;
+        lock.lock();
+        try {
+            tempFlag = thFlag;
+            thFlag++;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            lock.unlock();
+        }
+        requestTicket(prList[tempFlag], ktOptions, tempFlag);
+    }
+
+    /**
+     * Convert kinit tool options to KOptions.
+     * @param toolOptions
+     * @return KOptions
+     */
+    static KOptions convertOptions(KOptions toolOptions) {
+        KOptions results = new KOptions();
+
+        for (KOption toolOpt : toolOptions.getOptions()) {
+            KOptionInfo kOptionInfo = toolOpt.getOptionInfo();
+            KOptionGroup group = kOptionInfo.getGroup();
+            KOption kOpt = null;
+
+            if (group == KrbOptionGroup.KRB) {
+                kOpt = KrbOption.fromOptionName(kOptionInfo.getName());
+            } else if (group == KrbOptionGroup.PKINIT) {
+                kOpt = PkinitOption.fromOptionName(kOptionInfo.getName());
+            } else if (group == KrbOptionGroup.TOKEN) {
+                kOpt = TokenOption.fromOptionName(kOptionInfo.getName());
+            } else if (group == KrbOptionGroup.KDC_FLAGS) {
+                kOpt = KrbKdcOption.fromOptionName(kOptionInfo.getName());
+            }
+            if (kOpt != null && kOpt.getOptionInfo() != KrbOption.NONE.getOptionInfo()) {
+                kOpt.getOptionInfo().setValue(toolOpt.getOptionInfo().getValue());
+                results.add(kOpt);
+            }
+        }
+
+        return results;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java
----------------------------------------------------------------------
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java
index 224c9ed..1c97204 100644
--- a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/KadminTool.java
@@ -34,6 +34,7 @@ import org.apache.kerby.kerberos.tool.kadmin.command.KeytabRemoveCommand;
 import org.apache.kerby.kerberos.tool.kadmin.command.ListPrincipalCommand;
 import org.apache.kerby.kerberos.tool.kadmin.command.ModifyPrincipalCommand;
 import org.apache.kerby.kerberos.tool.kadmin.command.RenamePrincipalCommand;
+import org.apache.kerby.kerberos.tool.kadmin.command.AddPrincipalsCommand;
 import org.apache.kerby.util.OSUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,6 +57,8 @@ public class KadminTool {
             + "\n"
             + "add_principal, addprinc, ank\n"
             + "                         Add principal\n"
+            + "batch_anks, batch\n"
+            + "                         Add principals\n"
             + "delete_principal, delprinc\n"
             + "                         Delete principal\n"
             + "modify_principal, modprinc\n"
@@ -121,6 +124,9 @@ public class KadminTool {
                 || command.startsWith("addprinc")
                 || command.startsWith("ank")) {
             executor = new AddPrincipalCommand(kadmin);
+        } else if (command.startsWith("batch_anks")
+                || command.startsWith("batch")) {
+            executor = new AddPrincipalsCommand(kadmin);
         } else if (command.startsWith("ktadd")
                 || command.startsWith("xst")) {
             executor = new KeytabAddCommand(kadmin);

http://git-wip-us.apache.org/repos/asf/directory-kerby/blob/74147325/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java
----------------------------------------------------------------------
diff --git a/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java
new file mode 100644
index 0000000..32fe808
--- /dev/null
+++ b/kerby-tool/kdc-tool/src/main/java/org/apache/kerby/kerberos/tool/kadmin/command/AddPrincipalsCommand.java
@@ -0,0 +1,112 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.kerby.kerberos.tool.kadmin.command;
+
+import org.apache.kerby.KOptions;
+import org.apache.kerby.kerberos.kerb.KrbException;
+import org.apache.kerby.kerberos.kerb.admin.LocalKadmin;
+import org.apache.kerby.kerberos.kerb.admin.KadminOption;
+import org.apache.kerby.kerberos.tool.kadmin.ToolUtil;
+
+public class AddPrincipalsCommand extends KadminCommand {
+    private static final String USAGE = "Usage: add_principals [options]\n"
+            + "\toptions are:\n"
+            + "[-pwexpire pwexpdate] [-maxlife maxtixlife]\n"
+            + "\t\t[-kvno kvno] [-policy policy] [-clearpolicy]\n"
+            + "\t\t[-size principal's numbers,must be greater than zero]\n"
+            + "\t\t[-e keysaltlist]\n"
+            + "\t\t[{+|-}attribute]\n"
+            + "\tattributes are:\n"
+            + "\t\tallow_postdated allow_forwardable allow_tgs_req allow_renewable\n"
+            + "\t\tallow_proxiable allow_dup_skey allow_tix requires_preauth\n"
+            + "\t\trequires_hwauth needchange allow_svr password_changing_service\n"
+            + "\t\tok_as_delegate ok_to_auth_as_delegate no_auth_data_required\n"
+            + "\n"
+            + "\twhere,\n"
+            + "\t[-x db_princ_args]* - any number of database specific arguments.\n"
+            + "\t\t\tLook at each database documentation for supported arguments.\n"
+            + "\tExample:\n"
+            + "\t\tbatch_anks -expire 23/04/15:01:01:01 -kvno 1 -size 6";
+
+
+    private KOptions kOptions;
+
+    public AddPrincipalsCommand(LocalKadmin kadmin) {
+        super(kadmin);
+    }
+
+    @Override
+    public void execute(String input) {
+        String[] commands = input.split("\\s+");
+        if (commands.length < 2) {
+            System.err.println(USAGE);
+            return;
+        }
+        kOptions = ToolUtil.parseOptions(commands, 1, commands.length - 1);
+
+        int size;
+        if (kOptions.contains(KadminOption.SIZE)) {
+            String sizeTemp = kOptions.getStringOption(KadminOption.SIZE);
+
+            String isNum = "^[1-9][0-9]+";
+            if (sizeTemp.matches(isNum)) {
+                size = Integer.parseInt(sizeTemp);
+            } else {
+                System.err.println(USAGE);
+                return;
+            }
+        } else {
+            System.err.println(USAGE);
+            return;
+        }
+
+        if (size <= 0) {
+            System.err.println(USAGE);
+            return;
+        }
+
+        int existNumbers = 0;
+        try {
+            existNumbers = getKadmin().size();
+        } catch (KrbException e) {
+            e.printStackTrace();
+            return;
+        }
+
+        addPrincipalForSize(size, existNumbers);
+    }
+
+    private void addPrincipalForSize(int size, int existNumbers) {
+        int i = 0;
+        while (i < size) {
+            try {
+                int temp = i + existNumbers;
+                String principalName = "E" + temp + "@EXAMPLE.COM";
+                String password = "12";
+                getKadmin().addPrincipal(principalName, password, kOptions);
+            } catch (KrbException e) {
+                e.printStackTrace();
+            }
+            i++;
+        }
+
+        System.out.println("Principals created");
+    }
+}