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-3414 Commit: 4897315b33a59e8566ffd026e99445279f27c53a Parents: 6389400 Author: Andrey Novikov <[email protected]> Authored: Fri Jul 15 16:54:21 2016 +0700 Committer: Andrey Novikov <[email protected]> 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
