You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by vo...@apache.org on 2016/09/06 14:39:51 UTC

[29/50] [abbrv] ignite git commit: IGNITE-3446 Visor CMD: improve usability for batch mode.

IGNITE-3446 Visor CMD: improve usability for batch mode.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/4897315b
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/4897315b
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/4897315b

Branch: refs/heads/ignite-1.5.31-1
Commit: 4897315b33a59e8566ffd026e99445279f27c53a
Parents: 6389400
Author: Andrey Novikov <an...@apache.org>
Authored: Fri Jul 15 16:54:21 2016 +0700
Committer: Andrey Novikov <an...@apache.org>
Committed: Fri Jul 15 16:54:21 2016 +0700

----------------------------------------------------------------------
 .../ignite/visor/commands/VisorConsole.scala    |   5 +-
 .../commands/alert/VisorAlertCommand.scala      |   2 +-
 .../commands/cache/VisorCacheCommand.scala      |  40 ++--
 .../commands/cache/VisorCacheStopCommand.scala  |   2 +-
 .../config/VisorConfigurationCommand.scala      |  23 ++-
 .../commands/events/VisorEventsCommand.scala    |  29 +--
 .../visor/commands/gc/VisorGcCommand.scala      |  11 +-
 .../visor/commands/kill/VisorKillCommand.scala  | 184 ++++++++++++++-----
 .../visor/commands/node/VisorNodeCommand.scala  |  13 +-
 .../visor/commands/vvm/VisorVvmCommand.scala    |  11 +-
 .../scala/org/apache/ignite/visor/visor.scala   |  76 +++++---
 11 files changed, 276 insertions(+), 120 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
index 6d91b05..b4d78b5 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/VisorConsole.scala
@@ -146,7 +146,10 @@ class VisorConsole {
         batchCommand.foreach(commands => batchStream = Some(commands.replaceAll(";", "\n")))
 
         val inputStream = batchStream match {
-            case Some(cmd) => new ByteArrayInputStream((cmd + "\nquit\n").getBytes("UTF-8"))
+            case Some(cmd) =>
+                visor.batchMode = true
+
+                new ByteArrayInputStream((cmd + "\nquit\n").getBytes("UTF-8"))
             case None => new FileInputStream(FileDescriptor.in)
         }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala
index db60443..401a3f2 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/alert/VisorAlertCommand.scala
@@ -751,7 +751,7 @@ private case class VisorSentAlert(
     assert(spec != null)
 
     def idVar: String = {
-        val v = mfind(id)
+        val v = mfindHead(id)
 
         if (v.isDefined) id + "(@" + v.get._1 + ")" else id
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
index b4ed6b8..a9f9137 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheCommand.scala
@@ -73,12 +73,15 @@ import scala.language.{implicitConversions, reflectiveCalls}
  *
  * ====Arguments====
  * {{{
- *     -id=<node-id>
- *         Full ID of the node to get cache statistics from.
- *         Either '-id8' or '-id' can be specified.
- *         If neither is specified statistics will be gathered from all nodes.
  *     -id8=<node-id>
  *         ID8 of the node to get cache statistics from.
+ *         Note that either '-id8' or '-id' should be specified.
+ *         You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.
+ *         To specify oldest node on the same host as visor use variable '@nl'.
+ *         To specify oldest node on other hosts that are not running visor use variable '@nr'.
+ *         If neither is specified statistics will be gathered from all nodes.
+ *     -id=<node-id>
+ *         Full ID of the node to get cache statistics from.
  *         Either '-id8' or '-id' can be specified.
  *         If neither is specified statistics will be gathered from all nodes.
  *     -c=<cache-name>
@@ -278,7 +281,7 @@ class VisorCacheCommand {
                             else if (hasArgFlag("swap", argLst))
                                 VisorCacheSwapCommand().swap(argLst, node)
                             else if (hasArgFlag("stop", argLst))
-                                VisorCacheStopCommand().scan(argLst, node)
+                                VisorCacheStopCommand().stop(argLst, node)
                         }
                         else {
                             if (hasArgFlag("clear", argLst))
@@ -311,7 +314,12 @@ class VisorCacheCommand {
                 return
             }
 
-            println("Time of the snapshot: " + formatDateTime(System.currentTimeMillis))
+            node match {
+                case Some(n) =>
+                    println("ID8=" + nid8(n) + ", time of the snapshot: " + formatDateTime(System.currentTimeMillis))
+                case None =>
+                    println("Time of the snapshot: " + formatDateTime(System.currentTimeMillis))
+            }
 
             val sumT = VisorTextTable()
 
@@ -459,12 +467,12 @@ class VisorCacheCommand {
      */
     private def mkCacheName(@Nullable s: String): String = {
         if (s == null) {
-            val v = mfind(DFLT_CACHE_KEY)
+            val v = mfindHead(DFLT_CACHE_KEY)
 
             DFLT_CACHE_NAME + (if (v.isDefined) "(@" + v.get._1 + ')' else "")
         }
         else {
-            val v = mfind(s)
+            val v = mfindHead(s)
 
             s + (if (v.isDefined) "(@" + v.get._1 + ')' else "")
         }
@@ -649,7 +657,7 @@ class VisorCacheCommand {
 
         sumT.render()
 
-        val a = ask("\nChoose cache number ('c' to cancel) [c]: ", "c")
+        val a = ask("\nChoose cache number ('c' to cancel) [c]: ", "0")
 
         if (a.toLowerCase == "c")
             None
@@ -703,17 +711,19 @@ object VisorCacheCommand {
             "cache -stop -c=<cache-name>"
     ),
         args = Seq(
+            "-id8=<node-id>" -> Seq(
+                "ID8 of the node to get cache statistics from.",
+                "Note that either '-id8' or '-id' should be specified.",
+                "You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.",
+                "To specify oldest node on the same host as visor use variable '@nl'.",
+                "To specify oldest node on other hosts that are not running visor use variable '@nr'.",
+                "If neither is specified statistics will be gathered from all nodes."
+            ),
             "-id=<node-id>" -> Seq(
                 "Full ID of the node to get cache statistics from.",
                 "Either '-id8' or '-id' can be specified.",
                 "If neither is specified statistics will be gathered from all nodes."
             ),
-            "-id8=<node-id>" -> Seq(
-                "ID8 of the node to get cache statistics from.",
-                "Either '-id8' or '-id' can be specified.",
-                "If neither is specified statistics will be gathered from all nodes.",
-                "Note you can also use '@n0' ... '@nn' variables as shortcut to <node-id>."
-            ),
             "-c=<cache-name>" -> Seq(
                 "Name of the cache.",
                 "Note you can also use '@c0' ... '@cn' variables as shortcut to <cache-name>."

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheStopCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheStopCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheStopCommand.scala
index bf81f73..1b55505 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheStopCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/cache/VisorCacheStopCommand.scala
@@ -76,7 +76,7 @@ class VisorCacheStopCommand {
      *
      * @param argLst Command arguments.
      */
-    def scan(argLst: ArgList, node: Option[ClusterNode]) {
+    def stop(argLst: ArgList, node: Option[ClusterNode]) {
         val cacheArg = argValue("c", argLst)
 
         val cacheName = cacheArg match {

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala
index 3f0f52f..1b8bbd5 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/config/VisorConfigurationCommand.scala
@@ -54,12 +54,16 @@ import scala.language.implicitConversions
  *
  * ====Arguments====
  * {{{
+ *     -id8=<node-id8>
+ *         Node ID8.
+ *         Note that either '-id8' or '-id' should be specified.
+ *         You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.
+ *         To specify oldest node on the same host as visor use variable '@nl'.
+ *         To specify oldest node on other hosts that are not running visor use variable '@nr'.
+ *         If neither is specified - command starts in interactive mode.
  *     -id=<node-id>
  *         Full node ID. Either '-id8' or '-id' can be specified.
  *         If neither is specified - command starts in interactive mode.
- *     -id8=<node-id8>
- *         Node ID8. Either '-id8' or '-id' can be specified.
- *         If neither is specified - command starts in interactive mode.
  * }}}
  *
  * ====Examples====
@@ -388,14 +392,17 @@ object VisorConfigurationCommand {
             s"${cmd.name} {-id=<node-id>|id8=<node-id8>}"
         ),
         args = List(
+            "-id8=<node-id8>" -> List(
+                "Node ID8.",
+                "Note that either '-id8' or '-id' should be specified.",
+                "You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.",
+                "To specify oldest node on the same host as visor use variable '@nl'.",
+                "To specify oldest node on other hosts that are not running visor use variable '@nr'.",
+                "If neither is specified - command starts in interactive mode."
+            ),
             "-id=<node-id>" -> List(
                 "Full node ID. Either '-id8' or '-id' can be specified.",
                 "If neither is specified - command starts in interactive mode."
-            ),
-            "-id8=<node-id8>" -> List(
-                "Node ID8. Either '-id8' or '-id' can be specified.",
-                "If neither is specified - command starts in interactive mode.",
-                "Note you can also use '@n0' ... '@nn' variables as shortcut to <node-id>."
             )
         ),
         examples = List(

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/VisorEventsCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/VisorEventsCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/VisorEventsCommand.scala
index f7ea625..e3e73c7 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/VisorEventsCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/VisorEventsCommand.scala
@@ -65,12 +65,15 @@ import scala.language.implicitConversions
  *
  * ====Arguments====
  * {{{
- *     -id=<node-id>
- *         Full node ID.
- *         Either '-id' or '-id8' can be specified.
- *         If called without the arguments - starts in interactive mode.
  *     -id8
  *         Node ID8.
+ *         Note that either '-id8' or '-id' should be specified.
+ *         You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.
+ *         To specify oldest node on the same host as visor use variable '@nl'.
+ *         To specify oldest node on other hosts that are not running visor use variable '@nr'.
+ *         If called without the arguments - starts in interactive mode.
+ *     -id=<node-id>
+ *         Full node ID.
  *         Either '-id' or '-id8' can be specified.
  *         If called without the arguments - starts in interactive mode.
  *     -e=<ch,de,di,jo,ta,ca,cr,sw>
@@ -146,7 +149,7 @@ class VisorEventsCommand extends VisorConsoleCommand {
      */
     @throws[IllegalArgumentException]("In case unknown event mnemonic.")
     protected def typeFilter(typeArg: Option[String]) = {
-        typeArg.map(_.split(",").map(typeIds).flatten).orNull
+        typeArg.map(_.split(",").flatMap(typeIds)).orNull
     }
 
     /**
@@ -229,6 +232,8 @@ class VisorEventsCommand extends VisorConsoleCommand {
                             return
                     }
 
+                    println("ID8=" + nid8(node))
+
                     if (evts == null || evts.isEmpty) {
                         println("No events found.")
 
@@ -402,17 +407,19 @@ object VisorEventsCommand {
             "    {-t=<num>s|m|h|d} {-s=e|t} {-r} {-c=<n>}"
         ),
         args = List(
+            "-id8=<node-id8>" -> List(
+                "Node ID8.",
+                "Note that either '-id8' or '-id' should be specified.",
+                "You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.",
+                "To specify oldest node on the same host as visor use variable '@nl'.",
+                "To specify oldest node on other hosts that are not running visor use variable '@nr'.",
+                "If called without the arguments - starts in interactive mode."
+            ),
             "-id=<node-id>" -> List(
                 "Full node ID.",
                 "Either '-id' or '-id8' can be specified.",
                 "If called without the arguments - starts in interactive mode."
             ),
-            "-id8=<node-id8>" -> List(
-                "Node ID8.",
-                "Note that either '-id8' or '-id' can be specified and " +
-                    "you can also use '@n0' ... '@nn' variables as shortcut to <node-id8>.",
-                "If called without the arguments - starts in interactive mode."
-            ),
             "-e=<ch,de,di,jo,ta,ca,cr,sw>" -> List(
                 "Comma separated list of event types that should be queried:",
                 "   ch Checkpoint events.",

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/VisorGcCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/VisorGcCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/VisorGcCommand.scala
index a9bf39f..990fd00 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/VisorGcCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/VisorGcCommand.scala
@@ -52,7 +52,10 @@ import scala.language.{implicitConversions, reflectiveCalls}
  * {{{
  *     -id8=<node-id8>
  *         ID8 of the node.
- *         Note that either '-id8' or '-id' can be specified.
+ *         Note that either '-id8' or '-id' should be specified.
+ *         You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.
+ *         To specify oldest node on the same host as visor use variable '@nl'.
+ *         To specify oldest node on other hosts that are not running visor use variable '@nr'.
  *     -id=<node-id>
  *         ID of the node.
  *         Note that either '-id8' or '-id' can be specified.
@@ -159,8 +162,10 @@ object VisorGcCommand {
         args = List(
             "-id8=<node-id8>" -> List(
                 "ID8 of the node.",
-                "Note that either '-id8' or '-id' can be specified and " +
-                    "you can also use '@n0' ... '@nn' variables as shortcut to <node-id8>."
+                "Note that either '-id8' or '-id' should be specified.",
+                "You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.",
+                "To specify oldest node on the same host as visor use variable '@nl'.",
+                "To specify oldest node on other hosts that are not running visor use variable '@nr'."
             ),
             "-id=<node-id>" -> List(
                 "ID of the node.",

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/VisorKillCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/VisorKillCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/VisorKillCommand.scala
index dffd5f1..c705e21 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/VisorKillCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/VisorKillCommand.scala
@@ -46,7 +46,7 @@ import scala.util.control.Breaks._
  * {{{
  *     kill
  *     kill "-in|-ih"
- *     kill "{-r|-k} {-id8=<node-id8>|-id=<node-id>}"
+ *     kill "{-r|-k} {-sc} {-al|-ar|-id8=<node-id8>|-id=<node-id>}"
  * }}}
  *
  * ====Arguments====
@@ -61,17 +61,28 @@ import scala.util.control.Breaks._
  *         Run command in interactive mode with ability to
  *         choose a host where to kill or restart nodes.
  *         Note that either '-in' or '-ih' can be specified.
+ *     -al
+ *         Kill or restart all nodes on this host.
+ *         Note that either '-al' or '-ar' can be specified.
+ *     -ar
+ *         Kill or restart all nodes on other hosts.
+ *         Note that either '-al', '-ar' can be specified.
+ *     -sc
+ *         Skip kill or restart of client nodes for group nodes command.
  *     -r
  *         Restart node mode.
  *         Note that either '-r' or '-k' can be specified.
- *         If no parameters provided - command starts in interactive mode.
+ *         If no other parameters provided - command executes on all nodes.
  *     -k
  *         Kill (stop) node mode.
  *         Note that either '-r' or '-k' can be specified.
- *         If no parameters provided - command starts in interactive mode.
+ *         If no other parameters provided - command executes on all nodes.
  *     -id8=<node-id8>
  *         ID8 of the node to kill or restart.
- *         Note that either '-id8' or '-id' can be specified.
+ *         Note that either '-id8' or '-id' should be specified.
+ *         You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.
+ *         To specify oldest node on the same host as visor use variable '@nl'.
+ *         To specify oldest node on other hosts that are not running visor use variable '@nr'.
  *         If no parameters provided - command starts in interactive mode.
  *     -id=<node-id>
  *         ID of the node to kill or restart.
@@ -85,6 +96,16 @@ import scala.util.control.Breaks._
  *         Starts command in interactive mode.
  *     kill "-id8=12345678 -r"
  *         Restart node with '12345678' ID8.
+ *     kill -id8=@n0 -r" ->
+ *         Restart specified node with id8 taken from 'n0' memory variable.
+ *     kill -id8=@nl -r" ->
+ *         Restart oldest local node with id8 taken from 'nl' memory variable.
+ *     kill -id8=@nl -k" ->
+ *         Kill (stop) oldest remote node with id8 taken from 'nr' memory variable.
+ *     kill -r -ar" ->
+ *         Restart all remote nodes.
+ *     kill -k -sc -al" ->
+ *         Kill (stop) all local server nodes.
  *     kill "-k"
  *         Kill (stop) all nodes.
  * }}}
@@ -114,8 +135,12 @@ class VisorKillCommand extends VisorConsoleCommand {
             val iNodes = hasArgFlag("in", argLst)
             val iHosts = hasArgFlag("ih", argLst)
 
+            val skipClient = hasArgFlag("sc", argLst)
+
             if (iNodes && iHosts)
                 scold("Only one of '-in' or '-ih' can be specified.").^^
+            else if ((iNodes || iHosts) && skipClient)
+                scold("Skip client flag is not allowed in interactive mode.").^^
             else if (iNodes)
                 interactiveNodes().^^
             else if (iHosts)
@@ -126,52 +151,94 @@ class VisorKillCommand extends VisorConsoleCommand {
             val restart = hasArgFlag("r", argLst)
             val kill = hasArgFlag("k", argLst)
 
-            var node: ClusterNode = null
+            val allLocal = hasArgFlag("al", argLst)
+            val allRemote = hasArgFlag("ar", argLst)
 
             if (kill && restart)
                 scold("Only one of '-k' or '-r' can be specified.")
             else if (!kill && !restart)
                 scold("Missing '-k' or '-r' option in command: " + args)
-            else if (id8.isDefined && id.isDefined)
-                scold("Only one of -id8 or -id is allowed.")
+            else if (Seq(allLocal, allRemote, id8.isDefined, id.isDefined).count((v) => v) > 1)
+                scold("Only one of -al, -ar, -id8 or -id is allowed.")
+            else if ((id8.isDefined || id.isDefined) && skipClient)
+                scold("Skip client flag is allowed only for group command.")
             else {
-                if (id8.isDefined) {
+                val localGroup = ignite.cluster.forHost(ignite.localNode)
+
+                var nodes = if (id8.isDefined) {
                     val ns = nodeById8(id8.get)
 
                     if (ns.isEmpty)
                         scold("Unknown 'id8' value: " + id8.get).^^
-                    else if (ns.size != 1) {
+
+                    if (ns.size != 1)
                         scold("'id8' resolves to more than one node (use full 'id' instead) : " + args).^^
-                    }
-                    else
-                        node = ns.head
+
+                    ns.toSeq
                 }
-                else if (id.isDefined)
-                    try {
-                        node = ignite.cluster.node(java.util.UUID.fromString(id.get))
+                else if (id.isDefined) {
+                    var nid: UUID = null
 
-                        if (node == null)
-                            scold("'id' does not match any node : " + args).^^
+                    try {
+                        nid = UUID.fromString(id.get)
                     }
                     catch {
                         case e: IllegalArgumentException => scold("Invalid node 'id' in args: " + args).^^
                     }
 
-                if (node == null && (id.isDefined || id8.isDefined))
-                    scold("Node with given ID cannot be found.").^^
+                    val nodes = ignite.cluster.forNodeId(nid).nodes()
+
+                    if (nodes.isEmpty)
+                        scold("'id' does not match any node : " + args).^^
+
+                    nodes.toSeq
+                } else if (allLocal) {
+                    if (skipClient)
+                        localGroup.forServers().nodes().toSeq
+                    else
+                        localGroup.nodes().toSeq
+                }
+                else if (allRemote) {
+                    val remoteGroup = ignite.cluster.forOthers(localGroup)
+
+                    if (skipClient)
+                        remoteGroup.forServers().nodes().toSeq
+                    else
+                        remoteGroup.nodes().toSeq
+                }
+                else {
+                    if (skipClient)
+                        ignite.cluster.forServers().nodes().toSeq
+                    else
+                        ignite.cluster.nodes().toSeq
+                }
+
+                if (nodes.isEmpty) {
+                    if (id.isDefined || id8.isDefined)
+                        scold("Node with given ID cannot be found.").^^
+                    else if (allLocal)
+                        scold("Local nodes cannot be found.").^^
+                    else if (allRemote)
+                        scold("Remote nodes cannot be found.").^^
+                }
+
+                if (restart) {
+                    val excludeNodes = nodes.filter(_.attribute[String](ATTR_RESTART_ENABLED) == "false")
+
+                    nodes = nodes.filter(_.attribute[String](ATTR_RESTART_ENABLED) == "true")
 
-                try
                     // In case of the restart - check that target node supports it.
-                    if (restart && node != null && node.attribute[String](ATTR_RESTART_ENABLED) != "true")
-                        scold("Node doesn't support restart: " + nid8(node)).^^
-                catch {
-                    case e: IgniteException => scold("Failed to restart the node. " + e.getMessage).^^
+                    if (excludeNodes.nonEmpty)
+                        scold("Node(s) doesn't support restart: " + excludeNodes.map(nid8).mkString("[", ", ", "]")).^^
+
+                    if (nodes.isEmpty)
+                        break
                 }
 
                 val op = if (restart) "restart" else "kill"
 
                 try
-                    killOrRestart(if (node == null) ignite.cluster.nodes().map(_.id()) else Collections.singleton(node.id()), restart)
+                    killOrRestart(nodes.map(_.id()), restart)
                 catch {
                     case _: IgniteException => scold("Failed to " + op + " due to system error.").^^
                 }
@@ -205,29 +272,31 @@ class VisorKillCommand extends VisorConsoleCommand {
 
         val op = if (restart) "restart" else "kill"
 
-        if (nodes.size == ignite.cluster.nodes().size())
-            ask("Are you sure you want to " + op + " ALL nodes? (y/n) [n]: ", "n") match {
-                case "y" | "Y" =>  ask("You are about to " + op + " ALL nodes. " +
-                    "Are you 100% sure? (y/n) [n]: ", "n") match {
+        if (!batchMode) {
+            if (nodes.size == ignite.cluster.nodes().size())
+                ask("Are you sure you want to " + op + " ALL nodes? (y/n) [n]: ", "n") match {
+                    case "y" | "Y" => ask("You are about to " + op + " ALL nodes. " +
+                        "Are you 100% sure? (y/n) [n]: ", "n") match {
                         case "y" | "Y" => ()
                         case "n" | "N" => break()
                         case x => nl(); warn("Invalid answer: " + x); break()
                     }
-                case "n" | "N" => break()
-                case x => nl(); warn("Invalid answer: " + x); break()
-            }
-        else if (nodes.size > 1)
-            ask("Are you sure you want to " + op + " several nodes? (y/n) [n]: ", "n") match {
-                case "y" | "Y" => ()
-                case "n" | "N" => break()
-                case x => nl(); warn("Invalid answer: " + x); break()
-            }
-        else
-            ask("Are you sure you want to " + op + " this node? (y/n) [n]: ", "n") match {
-                case "y" | "Y" => ()
-                case "n" | "N" => break()
-                case x => nl(); warn("Invalid answer: " + x); break()
-            }
+                    case "n" | "N" => break()
+                    case x => nl(); warn("Invalid answer: " + x); break()
+                }
+            else if (nodes.size > 1)
+                ask("Are you sure you want to " + op + " several nodes? (y/n) [n]: ", "n") match {
+                    case "y" | "Y" => ()
+                    case "n" | "N" => break()
+                    case x => nl(); warn("Invalid answer: " + x); break()
+                }
+            else
+                ask("Are you sure you want to " + op + " " + nid8(nodes.head) + " node? (y/n) [n]: ", "n") match {
+                    case "y" | "Y" => ()
+                    case "n" | "N" => break()
+                    case x => nl(); warn("Invalid answer: " + x); break()
+                }
+        }
 
         if (restart)
             ignite.cluster.restartNodes(nodes)
@@ -278,7 +347,7 @@ object VisorKillCommand {
         spec = List(
             cmd.name,
             s"${cmd.name} -in|-ih",
-            s"${cmd.name} {-r|-k} {-id8=<node-id8>|-id=<node-id>}"
+            s"${cmd.name} {-r|-k} {-sc} {-al|-ar|-id8=<node-id8>|-id=<node-id>}"
         ),
         args = List(
             "-in" -> List(
@@ -293,6 +362,17 @@ object VisorKillCommand {
                 "choose a host where to kill or restart nodes.",
                 "Note that either '-in' or '-ih' can be specified."
             ),
+            "-al" -> List(
+                "Kill (stop) all local nodes.",
+                "Note that either '-al' or '-ar' can be specified."
+            ),
+            "-ar" -> List(
+                "Kill (stop) all remote nodes.",
+                "Note that either '-al' or '-ar' can be specified."
+            ),
+            "-sc" -> List(
+                "Skip kill or restart of client nodes for group nodes command."
+            ),
             "-r" -> List(
                 "Restart node mode.",
                 "Note that either '-r' or '-k' can be specified.",
@@ -305,8 +385,10 @@ object VisorKillCommand {
             ),
             "-id8=<node-id8>" -> List(
                 "ID8 of the node to kill or restart.",
-                "Note that either '-id8' or '-id' can be specified and " +
-                    "you can also use '@n0' ... '@nn' variables as shortcut to <node-id8>.",
+                "Note that either '-id8' or '-id' should be specified.",
+                "You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.",
+                "To specify oldest node on the same host as visor use variable '@nl'.",
+                "To specify oldest node on other hosts that are not running visor use variable '@nr'.",
                 "If no parameters provided - command starts in interactive mode."
             ),
             "-id=<node-id>" -> List(
@@ -322,6 +404,14 @@ object VisorKillCommand {
                 "Restart node with id8.",
             s"${cmd.name} -id8=@n0 -r" ->
                 "Restart specified node with id8 taken from 'n0' memory variable.",
+            s"${cmd.name} -id8=@nl -r" ->
+                "Restart oldest local node with id8 taken from 'nl' memory variable.",
+            s"${cmd.name} -id8=@nl -k" ->
+                "Kill (stop) oldest remote node with id8 taken from 'nr' memory variable.",
+            s"${cmd.name} -r -ar" ->
+                "Restart all remote nodes.",
+            s"${cmd.name} -k -sc -al" ->
+                "Kill (stop) all local server nodes.",
             s"${cmd.name} -k" ->
                 "Kill (stop) all nodes."
         ),

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/node/VisorNodeCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/node/VisorNodeCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/node/VisorNodeCommand.scala
index 9ba0129..899e495 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/node/VisorNodeCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/node/VisorNodeCommand.scala
@@ -57,7 +57,11 @@ import scala.util.control.Breaks._
  * ====Arguments====
  * {{{
  *     -id8=<node-id8>
- *         ID8 of node. Either '-id8' or '-id' can be specified.
+ *         ID8 of node.
+ *         Note that either '-id8' or '-id' should be specified.
+ *         You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.
+ *         To specify oldest node on the same host as visor use variable '@nl'.
+ *         To specify oldest node on other hosts that are not running visor use variable '@nr'.
  *         If neither specified - command starts in interactive mode.
  *     -id=<node-id>
  *         Full ID of node. Either '-id8' or '-id' can  be specified.
@@ -295,8 +299,11 @@ object VisorNodeCommand {
         ),
         args = List(
             "-id8=<node-id8>" -> List(
-                "Note that either '-id8' or '-id' can be specified and " +
-                    "you can also use '@n0' ... '@nn' variables as shortcut to <node-id8>.",
+                "ID8 of node.",
+                "Note that either '-id8' or '-id' should be specified.",
+                "You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.",
+                "To specify oldest node on the same host as visor use variable '@nl'.",
+                "To specify oldest node on other hosts that are not running visor use variable '@nr'.",
                 "If neither specified - command starts in interactive mode."
             ),
             "-id=<node-id>" -> List(

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommand.scala
index ff5cf82..e935256 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommand.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/vvm/VisorVvmCommand.scala
@@ -60,7 +60,10 @@ import scala.util.control.Breaks._
  *         If not specified, PATH and JAVA_HOME will be searched.
  *     -id8=<node-id8>
  *         ID8 of node.
- *         Either '-id8' or '-id' can be specified.
+ *         Note that either '-id8' or '-id' should be specified.
+ *         You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.
+ *         To specify oldest node on the same host as visor use variable '@nl'.
+ *         To specify oldest node on other hosts that are not running visor use variable '@nr'.
  *     -id=<node-id>
  *         Full ID of node.
  *         Either '-id8' or '-id' can be specified.
@@ -260,8 +263,10 @@ object VisorVvmCommand {
             ),
             "-id8=<node-id8>" -> List(
                 "ID8 of node.",
-                "Note that either '-id8' or '-id' can be specified and " +
-                    "you can also use '@n0' ... '@nn' variables as shortcut to <node-id8>."
+                "Note that either '-id8' or '-id' should be specified.",
+                "You can also use '@n0' ... '@nn' variables as a shortcut for <node-id8>.",
+                "To specify oldest node on the same host as visor use variable '@nl'.",
+                "To specify oldest node on other hosts that are not running visor use variable '@nr'."
             ),
             "-id=<node-id>" -> List(
                 "Full ID of node.",

http://git-wip-us.apache.org/repos/asf/ignite/blob/4897315b/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
index 7f7d1f9..1e8b634 100644
--- a/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/visor.scala
@@ -234,6 +234,8 @@ object visor extends VisorTag {
 
     private var reader: ConsoleReader = null
 
+    var batchMode: Boolean = false
+
     def reader(reader: ConsoleReader) {
         assert(reader != null)
 
@@ -661,12 +663,18 @@ object visor extends VisorTag {
     }
 
     /**
-     * Finds variable by its value.
+     * Finds variables by its value.
      *
      * @param v Value to find by.
      */
-    def mfind(@Nullable v: String): Option[(String, String)] =
-        mem find(t => t._2 == v)
+    def mfind(@Nullable v: String) = mem.filter(t => t._2 == v).toSeq
+
+    /**
+      * Finds variable by its value.
+      *
+      * @param v Value to find by.
+      */
+    def mfindHead(@Nullable v: String) = mfind(v).filterNot(entry => Seq("nl", "nr").contains(entry._1)).headOption
 
     /**
      * Sets Visor console memory variable. Note that this method '''does not'''
@@ -872,7 +880,7 @@ object visor extends VisorTag {
                 case _ => Left("'id8' resolves to more than one node (use full 'id' instead): " + id8.get)
             }
         }
-        else if (id.isDefined)
+        else if (id.isDefined) {
             try {
                 val node = Option(ignite.cluster.node(java.util.UUID.fromString(id.get)))
 
@@ -884,6 +892,7 @@ object visor extends VisorTag {
             catch {
                 case e: IllegalArgumentException => Left("Invalid node 'id': " + id.get)
             }
+        }
         else
             Right(None)
     }
@@ -1522,15 +1531,27 @@ object visor extends VisorTag {
                 setVarIfAbsent(ip.get, "h")
         })
 
+        val onHost = ignite.cluster.forHost(ignite.localNode())
+
+        Option(onHost.forServers().forOldest().node()).foreach(n => msetOpt("nl", nid8(n)))
+        Option(ignite.cluster.forOthers(onHost).forServers.forOldest().node()).foreach(n => msetOpt("nr", nid8(n)))
+
         nodeJoinLsnr = new IgnitePredicate[Event]() {
             override def apply(e: Event): Boolean = {
                 e match {
                     case de: DiscoveryEvent =>
-                        setVarIfAbsent(nid8(de.eventNode()), "n")
+                        val n = nid8(de.eventNode())
+
+                        setVarIfAbsent(n, "n")
 
                         val node = ignite.cluster.node(de.eventNode().id())
 
                         if (node != null) {
+                            val alias = if (U.sameMacs(ignite.localNode(), node)) "nl" else "nr"
+
+                            if (mgetOpt(alias).isEmpty)
+                                msetOpt(alias, n)
+
                             val ip = sortAddresses(node.addresses).headOption
 
                             if (ip.isDefined)
@@ -1551,29 +1572,25 @@ object visor extends VisorTag {
 
         ignite.events().localListen(nodeJoinLsnr, EVT_NODE_JOINED)
 
-        nodeLeftLsnr = new IgnitePredicate[Event]() {
-            override def apply(e: Event): Boolean = {
-                e match {
-                    case (de: DiscoveryEvent) =>
-                        val nv = mfind(nid8(de.eventNode()))
+        val mclear = (node: ClusterNode) => {
+            mfind(nid8(node)).foreach(nv => mem.remove(nv._1))
 
-                        if (nv.isDefined)
-                            mem.remove(nv.get._1)
+            val onHost = ignite.cluster.forHost(ignite.localNode())
 
-                        val ip = sortAddresses(de.eventNode().addresses).headOption
+            if (mgetOpt("nl").isEmpty)
+                Option(onHost.forServers().forOldest().node()).foreach(n => msetOpt("nl", nid8(n)))
 
-                        if (ip.isDefined) {
-                            val last = !ignite.cluster.nodes().exists(n =>
-                                n.addresses.size > 0 && sortAddresses(n.addresses).head == ip.get
-                            )
+            if (mgetOpt("nr").isEmpty)
+                Option(ignite.cluster.forOthers(onHost).forServers.forOldest().node()).foreach(n => msetOpt("nr", nid8(n)))
 
-                            if (last) {
-                                val hv = mfind(ip.get)
+            if (onHost.nodes().isEmpty)
+                sortAddresses(node.addresses).headOption.foreach((ip) => mfind(ip).foreach(hv => mem.remove(hv._1)))
+        }
 
-                                if (hv.isDefined)
-                                    mem.remove(hv.get._1)
-                            }
-                        }
+        nodeLeftLsnr = new IgnitePredicate[Event]() {
+            override def apply(e: Event): Boolean = {
+                e match {
+                    case (de: DiscoveryEvent) => mclear(de.eventNode())
                 }
 
                 true
@@ -1594,6 +1611,8 @@ object visor extends VisorTag {
 
                             close()
                         }
+                        else
+                            mclear(de.eventNode())
                 }
 
                 true
@@ -1658,7 +1677,7 @@ object visor extends VisorTag {
             val n = ignite.cluster.node(id)
 
             val id8 = nid8(id)
-            val v = mfind(id8)
+            val v = mfindHead(id8)
 
             id8 +
                 (if (v.isDefined) "(@" + v.get._1 + ")" else "") +
@@ -1678,7 +1697,7 @@ object visor extends VisorTag {
         assert(isCon)
 
         val id8 = nid8(id)
-        val v = mfind(id8)
+        val v = mfindHead(id8)
 
         id8 + (if (v.isDefined) "(@" + v.get._1 + ")" else "")
     }
@@ -1846,7 +1865,7 @@ object visor extends VisorTag {
 
             t.render()
 
-            val a = ask("\nChoose node number ('c' to cancel) [c]: ", "c")
+            val a = ask("\nChoose node number ('c' to cancel) [0]: ", "0")
 
             if (a.toLowerCase == "c")
                 None
@@ -1929,7 +1948,7 @@ object visor extends VisorTag {
 
             t.render()
 
-            val a = ask("\nChoose host number ('c' to cancel) [c]: ", "c")
+            val a = ask("\nChoose host number ('c' to cancel) [0]: ", "0")
 
             if (a.toLowerCase == "c")
                 None
@@ -2000,6 +2019,9 @@ object visor extends VisorTag {
         assert(prompt != null)
         assert(dflt != null)
 
+        if (batchMode)
+            return dflt
+
         readLineOpt(prompt, if (passwd) Some('*') else None) match {
             case None => dflt
             case Some(s) if s.length == 0 => dflt