ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject [39/50] [abbrv] incubator-ignite git commit: # ignite-63
Date Fri, 23 Jan 2015 09:02:47 GMT
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/Packet.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/Packet.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/Packet.scala
new file mode 100644
index 0000000..8d73288
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/Packet.scala
@@ -0,0 +1,76 @@
+/*
+ * 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.ignite.visor.commands
+
+/**
+ * ==Overview==
+ * Visor 'deploy' command implementation.
+ *
+ * ==Help==
+ * {{{
+ * +---------------------------------------------------+
+ * | deploy | Copies file or directory to remote host. |
+ * |        | Command relies on SFTP protocol.         |
+ * +---------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     deploy "-h={<username>{:<password>}@}<host>{:<port>} {-u=<username>}
+ *         {-p=<password>} {-k=<path>} -s=<path> {-d<path>}"
+ * }}}
+ *
+ * ====Arguments====
+ * {{{
+ *     -h={<username>{:<password>}@}<host>{:<port>}
+ *         Host specification.
+ *
+ *         <host> can be a hostname, IP or range of IPs.
+ *         Example of range is 192.168.1.100~150,
+ *         which means all IPs from 192.168.1.100 to 192.168.1.150 inclusively.
+ *
+ *         Default port number is 22.
+ *
+ *         This option can be provided multiple times.
+ *     -u=<username>
+ *         Default username.
+ *         Used if specification doesn't contain username.
+ *         If default is not provided as well, current local username will be used.
+ *     -p=<password>
+ *         Default password.
+ *         Used if specification doesn't contain password.
+ *         If default is not provided as well, it will be asked interactively.
+ *     -k=<path>
+ *         Path to private key file.
+ *         If provided, it will be used for all specifications that doesn't contain password.
+ *     -s=<path>
+ *         Source path.
+ *     -d=<path>
+ *         Destination path (relative to GRIDGAIN_HOME).
+ *         If not provided, files will be copied to the root of GRIDGAIN_HOME.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     deploy "-h=uname:passwd@host -s=/local/path -d=/remote/path"
+ *         Copies file or directory to remote host (password authentication).
+ *     deploy "-h=uname@host -k=ssh-key.pem -s=/local/path -d=/remote/path"
+ *         Copies file or directory to remote host (private key authentication).
+ * }}}
+ */
+package object deploy

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala
new file mode 100644
index 0000000..1ae70ea
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/deploy/VisorDeployCommand.scala
@@ -0,0 +1,613 @@
+/*
+ * 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.ignite.visor.commands.deploy
+
+import org.apache.ignite.internal.util.GridUtils
+import org.apache.ignite.internal.util.io.GridFilenameUtils
+import org.apache.ignite.internal.util.typedef.X
+
+import com.jcraft.jsch._
+
+import java.io._
+import java.net.UnknownHostException
+import java.util.concurrent._
+
+import org.apache.ignite.internal.util.typedef.internal.U
+import org.apache.ignite.visor.{VisorTag, visor}
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.VisorConsoleCommand
+import visor._
+
+import scala.language.{implicitConversions, reflectiveCalls}
+import scala.util.control.Breaks._
+
+/**
+ * Host data.
+ */
+private case class VisorHost(
+    name: String,
+    port: Int,
+    uname: String,
+    passwd: Option[String]
+) {
+    assert(name != null)
+    assert(port > 0)
+    assert(uname != null)
+    assert(passwd != null)
+
+    override def equals(r: Any) =
+        if (this eq r.asInstanceOf[AnyRef])
+            true
+        else if (r == null || !r.isInstanceOf[VisorHost])
+            false
+        else
+            r.asInstanceOf[VisorHost].name == name
+
+    override def hashCode() =
+        name.hashCode()
+}
+
+/**
+ * Runnable that copies file or directory.
+ */
+private case class VisorCopier(
+    host: VisorHost,
+    key: Option[String],
+    src: String,
+    dest: String
+) extends Runnable {
+    assert(host != null)
+    assert(key != null)
+    assert(src != null)
+    assert(dest != null)
+
+    assert(host.passwd.isDefined || key.isDefined)
+    assert(!(host.passwd.isDefined && key.isDefined))
+
+    /** SSH session. */
+    private var ses: Session = null
+
+    override def run() {
+        assert(ses == null)
+
+        val ssh = new JSch
+
+        if (key.isDefined)
+            ssh.addIdentity(key.get)
+
+        ses = ssh.getSession(host.uname, host.name, host.port)
+
+        if (host.passwd.isDefined)
+            ses.setPassword(host.passwd.get)
+
+        ses.setConfig("StrictHostKeyChecking", "no")
+
+        try {
+            ses.connect()
+
+            var ch: ChannelSftp = null
+
+            try {
+                val ggh = ggHome()
+
+                if (ggh == "")
+                    warn("GRIDGAIN_HOME is not set on " + host.name)
+                else {
+                    ch = ses.openChannel("sftp").asInstanceOf[ChannelSftp]
+
+                    ch.connect()
+
+                    copy(ch, src, GridFilenameUtils.separatorsToUnix(ggh + "/" + dest))
+
+                    println("ok => " + host.name)
+                }
+            }
+            finally {
+                if (ch != null && ch.isConnected)
+                    ch.disconnect()
+            }
+        }
+        catch {
+            case e: JSchException if X.hasCause(e, classOf[UnknownHostException]) =>
+                println("Visor Console failed to deploy. Reason: unknown host - " + host.name)
+
+            case e: JSchException =>
+                println("Visor Console failed to deploy. Reason: " + e.getMessage)
+
+            case e: Exception =>
+                warn(e.getMessage)
+        }
+        finally {
+            if (ses.isConnected)
+                ses.disconnect()
+        }
+    }
+
+    /**
+     * Gets `GRIDGAIN_HOME` from remote host.
+     *
+     * @return `GRIDGAIN_HOME` value.
+     */
+    private def ggHome(): String = {
+        /**
+         * Non interactively execute command.
+         *
+         * @param cmd command.
+         * @return command results
+         */
+        def exec(cmd: String) = {
+            val ch = ses.openChannel("exec").asInstanceOf[ChannelExec]
+
+            try {
+                ch.setCommand(cmd)
+
+                ch.connect()
+
+                new BufferedReader(new InputStreamReader(ch.getInputStream)).readLine
+            }
+            catch {
+                case e: JSchException =>
+                    warn(e.getMessage)
+
+                    ""
+            }
+            finally {
+                if (ch.isConnected)
+                    ch.disconnect()
+            }
+        }
+
+        /**
+         * Interactively execute command.
+         *
+         * @param cmd command.
+         * @return command results.
+         */
+        def shell(cmd: String): String = {
+            val ch = ses.openChannel("shell").asInstanceOf[ChannelShell]
+
+            try {
+                ch.connect()
+
+                // Added to skip login message.
+                GridUtils.sleep(1000)
+
+                val writer = new PrintStream(ch.getOutputStream, true)
+
+                val reader = new BufferedReader(new InputStreamReader(ch.getInputStream))
+
+                // Send command.
+                writer.println(cmd)
+
+                // Read echo command.
+                reader.readLine()
+
+                // Read command result.
+                reader.readLine()
+            }
+            catch {
+                case e: JSchException =>
+                    warn(e.getMessage)
+
+                    ""
+            }
+            finally {
+                if (ch.isConnected)
+                    ch.disconnect()
+            }
+        }
+
+        /**
+         * Checks whether host is running Windows OS.
+         *
+         * @return Whether host is running Windows OS.
+         * @throws JSchException In case of SSH error.
+         */
+        def windows = {
+            try
+                exec("cmd.exe") != null
+            catch {
+                case ignored: IOException => false
+            }
+        }
+
+        if (windows)
+            exec("echo %GRIDGAIN_HOME%")
+        else
+            shell("echo $GRIDGAIN_HOME") // Use interactive shell under nix because need read env from .profile and etc.
+    }
+
+    /**
+     * Copies file or directory.
+     *
+     * @param ch SFTP channel.
+     * @param src Source path.
+     * @param dest Destination path.
+     */
+    private def copy(ch: ChannelSftp, src: String, dest: String) {
+        assert(ch != null)
+        assert(src != null)
+        assert(dest != null)
+
+        val root = new File(src)
+
+        if (!root.exists)
+            throw new Exception("File or folder not found: " + src)
+
+        try {
+            if (root.isDirectory) {
+                try
+                    ch.ls(dest)
+                catch {
+                    case _: SftpException => ch.mkdir(dest)
+                }
+
+                root.listFiles.foreach(
+                    f => copy(ch, f.getPath, GridFilenameUtils.separatorsToUnix(dest + "/" + f.getName)))
+            }
+            else
+                ch.put(src, dest)
+        }
+        catch {
+            case e: SftpException =>
+                println("Visor Console failed to deploy from: " + src + " to: " + dest + ". Reason: " + e.getMessage)
+            case e: IOException =>
+                println("Visor Console failed to deploy from: " + src + " to: " + dest + ". Reason: " + e.getMessage)
+        }
+    }
+}
+
+/**
+ * ==Overview==
+ * Visor 'deploy' command implementation.
+ *
+ * ==Help==
+ * {{{
+ * +---------------------------------------------------+
+ * | deploy | Copies file or directory to remote host. |
+ * |        | Command relies on SFTP protocol.         |
+ * +---------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     deploy "-h={<username>{:<password>}@}<host>{:<port>} {-u=<username>}
+ *         {-p=<password>} {-k=<path>} -s=<path> {-d<path>}"
+ * }}}
+ *
+ * ====Arguments====
+ * {{{
+ *     -h={<username>{:<password>}@}<host>{:<port>}
+ *         Host specification.
+ *
+ *         <host> can be a hostname, IP or range of IPs.
+ *         Example of range is 192.168.1.100~150,
+ *         which means all IPs from 192.168.1.100 to 192.168.1.150 inclusively.
+ *
+ *         Default port number is 22.
+ *
+ *         This option can be provided multiple times.
+ *     -u=<username>
+ *         Default username.
+ *         Used if specification doesn't contain username.
+ *         If default is not provided as well, current local username will be used.
+ *     -p=<password>
+ *         Default password.
+ *         Used if specification doesn't contain password.
+ *         If default is not provided as well, it will be asked interactively.
+ *     -k=<path>
+ *         Path to private key file.
+ *         If provided, it will be used for all specifications that doesn't contain password.
+ *     -s=<path>
+ *         Source path.
+ *     -d=<path>
+ *         Destination path (relative to GRIDGAIN_HOME).
+ *         If not provided, files will be copied to the root of GRIDGAIN_HOME.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     deploy "-h=uname:passwd@host -s=/local/path -d=remote/path"
+ *         Copies file or directory to remote host (password authentication).
+ *     deploy "-h=uname@host -k=ssh-key.pem -s=/local/path -d=remote/path"
+ *         Copies file or directory to remote host (private key authentication).
+ * }}}
+ */
+class VisorDeployCommand {
+    /** Default port. */
+    private val DFLT_PORT = 22
+
+    /** String that specifies range of IPs. */
+    private val RANGE_SMB = "~"
+
+    /**
+     * Prints error message and advise.
+     *
+     * @param errMsgs Error messages.
+     */
+    private def scold(errMsgs: Any*) {
+        assert(errMsgs != null)
+
+        nl()
+
+        warn(errMsgs: _*)
+        warn("Type 'help deploy' to see how to use this command.")
+    }
+
+    /**
+     * Catch point for missing arguments case.
+     */
+    def deploy() {
+        scold("Missing arguments.")
+    }
+
+    /**
+     * ===Command===
+     * Copies file or directory to remote host.
+     *
+     * ===Examples===
+     * <ex>deploy "-h=uname:passwd@host -s=/local/path -d=/remote/path"</ex>
+     * Copies file or directory to remote host (password authentication).
+     *
+     * <ex>deploy "-h=uname@host -k=ssh-key.pem -s=/local/path -d=/remote/path"</ex>
+     * Copies file or directory to remote host (private key authentication).
+     */
+    def deploy(args: String) = breakable {
+        assert(args != null)
+
+        val argLst = parseArgs(args)
+
+        val dfltUname = argValue("u", argLst)
+        val dfltPasswd = argValue("p", argLst)
+        val key = argValue("k", argLst)
+        val src = argValue("s", argLst)
+        val dest = argValue("d", argLst)
+
+        if (!src.isDefined)
+            scold("Source is not defined.").^^
+
+        var hosts = Set.empty[VisorHost]
+
+        argLst.filter(_._1 == "h").map(_._2).foreach(h => {
+            try
+                hosts ++= mkHosts(h, dfltUname, dfltPasswd, key.isDefined)
+            catch {
+                case e: IllegalArgumentException => scold(e.getMessage).^^
+            }
+        })
+
+        if (hosts.isEmpty)
+            scold("At least one remote host should be specified.").^^
+
+        val copiers = hosts.map(VisorCopier(_, key, src.get, dest getOrElse ""))
+
+        try
+            copiers.map(pool.submit(_)).foreach(_.get)
+        catch {
+            case _: RejectedExecutionException => scold("Failed due to system error.").^^
+        }
+    }
+
+    /**
+     * Parses host string.
+     *
+     * @param host Host string.
+     * @param dfltUname `Option` for default username.
+     * @param dfltPasswd `Option` for default password.
+     * @param hasKey Whether private key file is defined.
+     * @return Set of `Host` instances.
+     */
+    private def mkHosts(
+        host: String,
+        dfltUname: Option[String],
+        dfltPasswd: Option[String],
+        hasKey: Boolean): Set[VisorHost] = {
+        assert(host != null)
+        assert(dfltUname != null)
+        assert(dfltPasswd != null)
+
+        assert(host != null)
+        assert(dfltUname != null)
+        assert(dfltPasswd != null)
+
+        var arr = host.split('@')
+
+        def extractHostsPort(s: String) = {
+            val hostPort = s.split(':')
+
+            val hosts = expandHost(hostPort(0))
+
+            val port =
+                try
+                    if (hostPort.size > 1) hostPort(1).toInt else DFLT_PORT
+                catch {
+                    case e: NumberFormatException =>
+                        scold("Invalid port number: " + hostPort(1)).^^
+
+                        // Never happens.
+                        0
+                }
+
+            if (port <= 0)
+                scold("Invalid port number: " + port).^^
+
+            (hosts, port)
+        }
+
+        if (arr.size == 1) {
+            val (hosts, port) = extractHostsPort(arr(0))
+
+            val uname = dfltUname getOrElse System.getProperty("user.name")
+            val passwd = if (!hasKey) Some(dfltPasswd getOrElse askPassword(uname)) else None
+
+            hosts.map(VisorHost(_, port, uname, passwd))
+        }
+        else if (arr.size == 2) {
+            val (hosts, port) = extractHostsPort(arr(1))
+
+            arr = arr(0).split(':')
+
+            val uname = arr(0)
+
+            val passwd =
+                if (arr.size > 1)
+                    Some(arr(1))
+                else if (!hasKey)
+                    Some(dfltPasswd getOrElse askPassword(uname))
+                else
+                    None
+
+            hosts.map(VisorHost(_, port, uname, passwd))
+        }
+        else {
+            scold("Invalid host string: " + host).^^
+
+            // Never happens.
+            Set.empty
+        }
+    }
+
+    /**
+     * Parses and expands range of IPs, if needed. Host names without the range
+     * returned as is.
+     *
+     * @param addr Host host with or without `~` range.
+     * @return Set of individual host names (IPs).
+     */
+    private def expandHost(addr: String): Set[String] = {
+        assert(addr != null)
+
+        if (addr.contains(RANGE_SMB)) {
+            val parts = addr.split(RANGE_SMB)
+
+            if (parts.size != 2)
+                scold("Invalid IP range: " + addr).^^
+
+            val lastDot = parts(0).lastIndexOf('.')
+
+            if (lastDot < 0)
+                scold("Invalid IP range: " + addr).^^
+
+            val (base, begin) = parts(0).splitAt(lastDot)
+            val end = parts(1)
+
+            try {
+                val a = begin.substring(1).toInt
+                val b = end.toInt
+
+                if (a > b)
+                    scold("Invalid IP range: " + addr).^^
+
+                (a to b).map(base + "." + _).toSet
+            }
+            catch {
+                case _: NumberFormatException =>
+                    scold("Invalid IP range: " + addr).^^
+
+                    // Never happens.
+                    Set.empty
+            }
+        }
+        else
+            Set(addr)
+    }
+
+    /**
+     * Interactively asks for password.
+     *
+     * @param uname Username.
+     * @return Password.
+     */
+    private def askPassword(uname: String): String = {
+        assert(uname != null)
+
+        ask("Password for '" + uname + "': ", "", true)
+    }
+}
+
+/**
+ * Companion object that does initialization of the command.
+ */
+object VisorDeployCommand {
+    addHelp(
+        name = "deploy",
+        shortInfo = "Copies file or folder to remote host.",
+        longInfo = List(
+            "Copies file or folder to remote host.",
+            "Command relies on SFTP protocol."
+        ),
+        spec = List(
+            "deploy -h={<username>{:<password>}@}<host>{:<port>} {-u=<username>}",
+            "    {-p=<password>} {-k=<path>} -s=<path> {-d<path>}"
+        ),
+        args = List(
+            "-h={<username>{:<password>}@}<host>{:<port>}" -> List(
+                "Host specification.",
+                " ",
+                "<host> can be a hostname, IP or range of IPs.",
+                "Example of range is 192.168.1.100~150,",
+                "which means all IPs from 192.168.1.100 to 192.168.1.150 inclusively.",
+                " ",
+                "Default port number is 22.",
+                " ",
+                "This option can be provided multiple times."
+            ),
+            "-u=<username>" -> List(
+                "Default username.",
+                "Used if specification doesn't contain username.",
+                "If default is not provided as well, current local username will be used."
+            ),
+            "-p=<password>" -> List(
+                "Default password.",
+                "Used if specification doesn't contain password.",
+                "If default is not provided as well, it will be asked interactively."
+            ),
+            "-k=<path>" -> List(
+                "Path to private key file.",
+                "If provided, it will be used for all specifications that doesn't contain password."
+            ),
+            "-s=<path>" -> "Source path.",
+            "-d=<path>" -> List(
+                "Destination path (relative to $GRIDGAIN_HOME).",
+                "If not provided, files will be copied to the root of $GRIDGAIN_HOME."
+            )
+        ),
+        examples = List(
+            "deploy -h=uname:passwd@host -s=/local/path -d=/remote/path" ->
+                "Copies file or folder to remote host (password authentication).",
+            "deploy -h=uname@host -k=ssh-key.pem -s=/local/path -d=/remote/path" ->
+                "Copies file or folder to remote host (private key authentication)."
+        ),
+        ref = VisorConsoleCommand(cmd.deploy, cmd.deploy)
+    )
+
+    /** Singleton command. */
+    private val cmd = new VisorDeployCommand
+
+    /**
+     * Singleton.
+     */
+    def apply() = cmd
+
+    /**
+     * Implicit converter from visor to commands "pimp".
+     *
+     * @param vs Visor tagging trait.
+     */
+    implicit def fromDeploy2Visor(vs: VisorTag) = cmd
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/Packet.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/Packet.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/Packet.scala
new file mode 100644
index 0000000..eb925f8
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/Packet.scala
@@ -0,0 +1,72 @@
+/*
+ * 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.ignite.visor.commands
+
+/**
+ * ==Overview==
+ * Visor 'disco' command implementation.
+ *
+ * ==Help==
+ * {{{
+ * +---------------------------------------------------------------------------------------+
+ * | disco | Prints topology change log as seen from the oldest node.                      |
+ * |       | Timeframe for quering events can be specified in arguments.                   |
+ * |       |                                                                               |
+ * |       | Note that this command depends on GridGain events.                            |
+ * |       |                                                                               |
+ * |       | GridGain events can be individually enabled and disabled and disabled events  |
+ * |       | can affect the results produced by this command. Note also that configuration |
+ * |       | of Event Storage SPI that is responsible for temporary storage of generated   |
+ * |       | events on each node can also affect the functionality of this command.        |
+ * |       |                                                                               |
+ * |       | By default - all events are enabled and GridGain stores last 10,000 local     |
+ * |       | events on each node. Both of these defaults can be changed in configuration.  |
+ * +---------------------------------------------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     disco
+ *     disco "{-t=<num>s|m|h|d} {-r} {-c=<n>}"
+ * }}}
+ *
+ * ====Arguments====
+ * {{{
+ *     -t=<num>s|m|h|d
+ *         Defines timeframe for querying events:
+ *            =<num>s Events fired during last <num> seconds.
+ *            =<num>m Events fired during last <num> minutes.
+ *            =<num>h Events fired during last <num> hours.
+ *            =<num>d Events fired during last <num> days.
+ *     -r
+ *         Defines whether sorting should be reversed.
+ *     -c=<n>
+ *         Defines the maximum events count that can be shown.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     disco
+ *         Prints all discovery events sorted chronologically (oldest first).
+ *     disco "-r"
+ *         Prints all discovery events sorted chronologically in reversed order (newest first).
+ *     disco "-t=2m"
+ *         Prints discovery events fired during last two minutes sorted chronologically.
+ * }}}
+ */
+package object disco

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommand.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommand.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommand.scala
new file mode 100644
index 0000000..34acaeb
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/disco/VisorDiscoveryCommand.scala
@@ -0,0 +1,307 @@
+/*
+ * 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.ignite.visor.commands.disco
+
+import org.apache.ignite.internal.util.GridUtils
+import org.apache.ignite.internal.util.typedef.internal.U
+import org.apache.ignite.internal.visor.event.VisorGridDiscoveryEvent
+import org.apache.ignite.internal.visor.node.VisorNodeEventsCollectorTask
+import org.apache.ignite.internal.visor.node.VisorNodeEventsCollectorTask.VisorNodeEventsCollectorTaskArg
+import org.apache.ignite.internal.util.lang.{GridFunc => F}
+
+import org.apache.ignite.cluster.ClusterNode
+import org.apache.ignite.events.IgniteEventType
+import org.apache.ignite.events.IgniteEventType._
+import org.apache.ignite.visor.{VisorTag, visor}
+
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.{VisorConsoleCommand, VisorTextTable}
+import visor._
+
+import scala.collection.JavaConversions._
+import scala.collection.immutable._
+import scala.language.{implicitConversions, reflectiveCalls}
+
+/**
+ * ==Overview==
+ * Visor 'disco' command implementation.
+ *
+ * ==Help==
+ * {{{
+ * +---------------------------------------------------------------------------------------+
+ * | disco | Prints topology change log as seen from the oldest node.                      |
+ * |       | Timeframe for querying events can be specified in arguments.                   |
+ * |       |                                                                               |
+ * |       | Note that this command depends on GridGain events.                            |
+ * |       |                                                                               |
+ * |       | GridGain events can be individually enabled and disabled and disabled events  |
+ * |       | can affect the results produced by this command. Note also that configuration |
+ * |       | of Event Storage SPI that is responsible for temporary storage of generated   |
+ * |       | events on each node can also affect the functionality of this command.        |
+ * |       |                                                                               |
+ * |       | By default - all events are DISABLED and GridGain stores last 10,000 local     |
+ * |       | events on each node. Both of these defaults can be changed in configuration.  |
+ * +---------------------------------------------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     disco
+ *     disco "{-t=<num>s|m|h|d} {-r} {-c=<n>}"
+ * }}}
+ *
+ * ====Arguments====
+ * {{{
+ *     -t=<num>s|m|h|d
+ *         Defines timeframe for querying events:
+ *            =<num>s Events fired during last <num> seconds.
+ *            =<num>m Events fired during last <num> minutes.
+ *            =<num>h Events fired during last <num> hours.
+ *            =<num>d Events fired during last <num> days.
+ *     -r
+ *         Defines whether sorting should be reversed.
+ *     -c=<n>
+ *         Defines the maximum events count that can be shown.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     disco
+ *         Prints all discovery events sorted chronologically (oldest first).
+ *     disco "-r"
+ *         Prints all discovery events sorted chronologically in reversed order (newest first).
+ *     disco "-t=2m"
+ *         Prints discovery events fired during last two minutes sorted chronologically.
+ * }}}
+ */
+class VisorDiscoveryCommand {
+    /** */
+    private type TimeFilter = EventFilter
+
+    /**
+     * Prints error message and advise.
+     *
+     * @param errMsgs Error messages.
+     */
+    private def scold(errMsgs: Any*) {
+        assert(errMsgs != null)
+
+        warn(errMsgs: _*)
+        warn("Type 'help disco' to see how to use this command.")
+    }
+
+    /**
+     * ===Command===
+     * Prints all discovery events.
+     *
+     * ===Examples===
+     * <ex>disco</ex>
+     * Prints all discovery events sorted chronologically (oldest first).
+     */
+    def disco() {
+        disco("")
+    }
+
+    /**
+     * ===Command===
+     * Prints discovery events within specified timeframe.
+     *
+     * ===Examples===
+     * <ex>disco "-r"</ex>
+     * Prints all discovery events sorted chronologically in reversed order (newest first).
+     *
+     * <ex>disco "-t=2m"</ex>
+     * Prints discovery events fired during last two minutes.
+     */
+    def disco(args: String) {
+        if (!isConnected)
+            adviseToConnect()
+        else {
+            val argLst = parseArgs(args)
+
+            val fs = argValue("t", argLst)
+
+            val tm = if (fs.isDefined) timeFilter(fs) else Long.MaxValue
+
+            if (tm > 0) {
+                val nodes = grid.nodes()
+
+                if (nodes.isEmpty) {
+                    scold("Topology is empty.")
+
+                    return
+                }
+
+                val oldest = grid.nodes().maxBy(_.metrics().getUpTime)
+
+                val cntOpt = argValue("c", argLst)
+
+                val cnt =
+                    try
+                        cntOpt.map(_.toInt).getOrElse(Int.MaxValue)
+                    catch {
+                        case e: NumberFormatException =>
+                            scold("Invalid count: " + cntOpt.get)
+
+                            return
+                    }
+
+                println("Oldest alive node in grid: " + nodeId8Addr(oldest.id))
+
+                val evts =
+                    try
+                        events(oldest, tm, hasArgFlag("r", argLst))
+                    catch {
+                        case e: Throwable =>
+                            scold(e.getMessage)
+
+                            return
+                    }
+
+                if (evts.isEmpty) {
+                    scold(
+                        "No discovery events found.",
+                        "Make sure events are not disabled and Event Storage SPI is properly configured."
+                    )
+
+                    return
+                }
+
+                nl()
+
+                if (evts.size > cnt)
+                    println("Top " + cnt + " Events:")
+                else
+                    println("All Events:")
+
+                val t = VisorTextTable()
+
+                // Spaces between ID8(@) and IP are intentional!
+                t #= ("Timestamp", "Event", "Node ID8(@)", "IP")
+
+                evts.take(cnt).foreach {
+                    case de: VisorGridDiscoveryEvent =>
+                        t +=(formatDateTime(de.timestamp()), de.name(),
+                            nodeId8(de.evtNodeId()) + (if (de.isDaemon) "(daemon)" else ""),
+                            if (F.isEmpty(de.address())) "<n/a>" else de.address())
+                    case _ =>
+                }
+
+                t.render()
+
+                nl()
+            }
+        }
+    }
+
+    /**
+     * Gets chronologically sorted list of discovery events.
+     *
+     * @param node Node.
+     * @param tmFrame Time frame to select events.
+     * @param reverse `True` if sort events in reverse order.
+     * @return Discovery events.
+     */
+    private def events(node: ClusterNode, tmFrame: Long, reverse: Boolean) = {
+        assert(node != null)
+        assert(!node.isDaemon)
+
+        var evts = grid.compute(grid.forNode(node)).execute(classOf[VisorNodeEventsCollectorTask],
+            toTaskArgument(node.id(), VisorNodeEventsCollectorTaskArg.createEventsArg(EVTS_DISCOVERY, tmFrame))).toSeq
+
+        val nodeStartTime = node.metrics().getStartTime
+
+        if (nodeStartTime > System.currentTimeMillis() - tmFrame) {
+            val root = new VisorGridDiscoveryEvent(EVT_NODE_JOINED, null, GridUtils.gridEventName(EVT_NODE_JOINED),
+                node.id(), nodeStartTime, "", "", node.id, node.addresses().head, node.isDaemon)
+
+            evts = Seq(root) ++ evts
+        }
+
+        evts = evts.sortBy(_.timestamp())
+
+        if (reverse) evts.reverse else evts
+    }
+}
+
+/**
+ * Companion object that does initialization of the command.
+ */
+object VisorDiscoveryCommand {
+    addHelp(
+        name = "disco",
+        shortInfo = "Prints topology change log.",
+        longInfo = List(
+            "Prints topology change log as seen from the oldest node.",
+            "Timeframe for querying events can be specified in arguments.",
+            " ",
+            "Note that this command depends on GridGain events.",
+            " ",
+            "GridGain events can be individually enabled and disabled and disabled events",
+            "can affect the results produced by this command. Note also that configuration",
+            "of Event Storage SPI that is responsible for temporary storage of generated",
+            "events on each node can also affect the functionality of this command.",
+            " ",
+            "By default - all events are disabled and GridGain stores last 10,000 local",
+            "events on each node. Both of these defaults can be changed in configuration."
+        ),
+        spec = List(
+            "disco",
+            "disco {-t=<num>s|m|h|d} {-r} {-c=<n>}"
+        ),
+        args = List(
+            "-t=<num>s|m|h|d" -> List(
+                "Defines timeframe for quering events:",
+                "   =<num>s Events fired during last <num> seconds.",
+                "   =<num>m Events fired during last <num> minutes.",
+                "   =<num>h Events fired during last <num> hours.",
+                "   =<num>d Events fired during last <num> days."
+            ),
+            "-r" -> List(
+                "Defines whether sorting should be reversed."
+            ),
+            "-c=<n>" -> List(
+                "Defines the maximum events count that can be shown."
+            )
+        ),
+        examples = List(
+            "disco" ->
+                "Prints all discovery events sorted chronologically (oldest first).",
+            "disco -r" ->
+                "Prints all discovery events sorted chronologically in reversed order (newest first).",
+            "disco -t=2m" ->
+                "Prints discovery events fired during last two minutes sorted chronologically."
+        ),
+        ref = VisorConsoleCommand(cmd.disco, cmd.disco)
+    )
+
+    /** Singleton command. */
+    private val cmd = new VisorDiscoveryCommand
+
+    /**
+     * Singleton.
+     */
+    def apply() = cmd
+
+    /**
+     * Implicit converter from visor to commands "pimp".
+     *
+     * @param vs Visor tagging trait.
+     */
+    implicit def fromDisco2Visor(vs: VisorTag) = cmd
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/Packet.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/Packet.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/Packet.scala
new file mode 100644
index 0000000..d21f5a3
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/Packet.scala
@@ -0,0 +1,97 @@
+/*
+ * 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.ignite.visor.commands
+
+/**
+ * ==Overview==
+ * Visor 'events' commands implementation.
+ *
+ * ==Help==
+ * {{{
+ * +----------------------------------------------------------------------------------------+
+ * | events | Print events from a node.                                                     |
+ * |        |                                                                               |
+ * |        | Note that this command depends on GridGain events.                            |
+ * |        |                                                                               |
+ * |        | GridGain events can be individually enabled and disabled and disabled events  |
+ * |        | can affect the results produced by this command. Note also that configuration |
+ * |        | of Event Storage SPI that is responsible for temporary storage of generated   |
+ * |        | events on each node can also affect the functionality of this command.        |
+ * |        |                                                                               |
+ * |        | By default - all events are enabled and GridGain stores last 10,000 local     |
+ * |        | events on each node. Both of these defaults can be changed in configuration.  |
+ * +----------------------------------------------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     events
+ *     events "{-id=<node-id>|-id8=<node-id8>} {-e=<ch,cp,de,di,jo,ta,cl,ca,sw>}
+ *         {-t=<num>s|m|h|d} {-s=e|t} {-r} {-c=<n>}"
+ * }}}
+ *
+ * ====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.
+ *         Either '-id' or '-id8' can be specified.
+ *         If called without the arguments - starts in interactive mode.
+ *     -e=<ch,de,di,jo,ta,cl,ca,sw>
+ *         Comma separated list of event types that should be queried:
+ *            ch Checkpoint events.
+ *            de Deployment events.
+ *            di Discovery events.
+ *            jo Job execution events.
+ *            ta Task execution events.
+ *            ca Cache events.
+ *            cp Cache pre-loader events.
+ *            sw Swapspace events.
+ *     -t=<num>s|m|h|d
+ *         Defines time frame for querying events:
+ *            =<num>s Queries events fired during last <num> seconds.
+ *            =<num>m Queries events fired during last <num> minutes.
+ *            =<num>h Queries events fired during last <num> hours.
+ *            =<num>d Queries events fired during last <num> days.
+ *     -s=e|t
+ *         Defines sorting of queried events:
+ *            =e Sorted by event type.
+ *            =t Sorted chronologically.
+ *         Only one '=e' or '=t' can be specified.
+ *     -r
+ *         Defines if sorting should be reversed.
+ *         Can be specified only with -s argument.
+ *     -c=<n>
+ *         Defines the maximum events count that can be shown.
+ *         Values in summary tables are calculated over the whole list of events.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     events "-id8=12345678"
+ *         Queries all events from node with '12345678' ID8.
+ *     events "-id8=12345678 -e=di,ca"
+ *         Queries discovery and cache events from node with '12345678' ID8.
+ *     events
+ *         Starts command in interactive mode.
+ * }}}
+ */
+package object events

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/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
new file mode 100644
index 0000000..93de9a3
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/events/VisorEventsCommand.scala
@@ -0,0 +1,531 @@
+/*
+ * 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.ignite.visor.commands.events
+
+import org.apache.ignite.internal.util.GridUtils
+import org.apache.ignite.internal.util.typedef.internal.U
+import org.apache.ignite.internal.visor.event.VisorGridEvent
+import org.apache.ignite.internal.visor.node.VisorNodeEventsCollectorTask
+import org.apache.ignite.internal.visor.node.VisorNodeEventsCollectorTask.VisorNodeEventsCollectorTaskArg
+
+import org.apache.ignite._
+import org.apache.ignite.events.IgniteEventType
+import org.apache.ignite.events.IgniteEventType._
+
+import java.util.UUID
+
+import org.apache.ignite.visor.VisorTag
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands._
+import visor.visor._
+
+import scala.collection.JavaConversions._
+import scala.collection.immutable._
+import scala.language.implicitConversions
+
+/**
+ * ==Overview==
+ * Visor 'events' commands implementation.
+ *
+ * ==Help==
+ * {{{
+ * +----------------------------------------------------------------------------------------+
+ * | events | Prints events from a node.                                                     |
+ * |        |                                                                               |
+ * |        | Note that this command depends on GridGain events.                            |
+ * |        |                                                                               |
+ * |        | GridGain events can be individually enabled and disabled and disabled events  |
+ * |        | can affect the results produced by this command. Note also that configuration |
+ * |        | of Event Storage SPI that is responsible for temporary storage of generated   |
+ * |        | events on each node can also affect the functionality of this command.        |
+ * |        |                                                                               |
+ * |        | By default - all events are DISABLED and GridGain stores last 10,000 local     |
+ * |        | events on each node. Both of these defaults can be changed in configuration.  |
+ * +----------------------------------------------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     events
+ *     events "{-id=<node-id>|-id8=<node-id8>} {-e=<ch,cp,de,di,jo,ta,cl,ca,sw>}
+ *         {-t=<num>s|m|h|d} {-s=e|t} {-r} {-c=<n>}"
+ * }}}
+ *
+ * ====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.
+ *         Either '-id' or '-id8' can be specified.
+ *         If called without the arguments - starts in interactive mode.
+ *     -e=<ch,de,di,jo,ta,ca,cp,sw,au>
+ *         Comma separated list of event types that should be queried:
+ *            ch Checkpoint events.
+ *            de Deployment events.
+ *            di Discovery events.
+ *            jo Job execution events.
+ *            ta Task execution events.
+ *            cl Cloud events.
+ *            ca Cache events.
+ *            cp Cache pre-loader events.
+ *            sw Swapspace events.
+ *            au Authentication events.
+              az Authorization events.
+              se Security session events.
+ *     -t=<num>s|m|h|d
+ *         Defines time frame for querying events:
+ *            =<num>s Queries events fired during last <num> seconds.
+ *            =<num>m Queries events fired during last <num> minutes.
+ *            =<num>h Queries events fired during last <num> hours.
+ *            =<num>d Queries events fired during last <num> days.
+ *     -s=e|t
+ *         Defines sorting of queried events:
+ *            =e Sorted by event type.
+ *            =t Sorted chronologically.
+ *         Only one '=e' or '=t' can be specified.
+ *     -r
+ *         Defines if sorting should be reversed.
+ *         Can be specified only with -s argument.
+ *     -c=<n>
+ *         Defines the maximum events count that can be shown.
+ *         Values in summary tables are calculated over the whole list of events.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     events "-id8=12345678"
+ *         Queries all events from node with '12345678' ID8.
+ *     events "-id8=12345678 -e=di,ca"
+ *         Queries discovery and cache events from node with '12345678' ID8.
+ *     events
+ *         Starts command in interactive mode.
+ * }}}
+ */
+class VisorEventsCommand {
+    /**
+     * Prints error message and advise.
+     *
+     * @param errMsgs Error messages.
+     */
+    private def scold(errMsgs: Any*) {
+        assert(errMsgs != null)
+
+        warn(errMsgs: _*)
+        warn("Type 'help events' to see how to use this command.")
+    }
+
+    /**
+     * ===Command===
+     * Starts command in interactive mode.
+     *
+     * ===Examples===
+     * <ex>events</ex>
+     * Starts command in interactive mode.
+     */
+    def events() {
+        if (!isConnected)
+            adviseToConnect()
+        else
+            askForNode("Select node from:") match {
+                case Some(id) => ask("Sort [c]ronologically or by [e]vent type (c/e) [c]: ", "c") match {
+                    case "c" | "C" => nl(); events("-s=t -id=" + id)
+                    case "e" | "E" => nl(); events("-s=e -id=" + id)
+                    case x => nl(); warn("Invalid answer: " + x)
+                }
+                case None => ()
+            }
+    }
+
+    private[this] def typeFilter(typeArg: Option[String]) = {
+        if (typeArg.isEmpty)
+            null
+        else {
+            val arr = collection.mutable.ArrayBuffer.empty[Int]
+
+            typeArg.get split "," foreach {
+                case "ch" => arr ++= EVTS_CHECKPOINT.toList
+                case "de" => arr ++= EVTS_DEPLOYMENT.toList
+                case "jo" => arr ++= EVTS_JOB_EXECUTION.toList
+                case "ta" => arr ++= EVTS_TASK_EXECUTION.toList
+                case "ca" => arr ++= EVTS_CACHE.toList
+                case "cp" => arr ++= EVTS_CACHE_PRELOAD.toList
+                case "sw" => arr ++= EVTS_SWAPSPACE.toList
+                case "di" => arr ++= EVTS_DISCOVERY.toList
+                case "au" => arr ++= EVTS_AUTHENTICATION.toList
+                case "az" => arr ++= EVTS_AUTHORIZATION.toList
+                case "se" => arr ++= EVTS_SECURE_SESSION.toList
+                case t => throw new IllegalArgumentException("Unknown event type: " + t)
+            }
+
+            arr.toArray
+        }
+    }
+
+    /**
+     * Gets command's mnemonic for given event.
+     *
+     * @param e Event to get mnemonic for.
+     */
+    private def mnemonic(e: VisorGridEvent): String = {
+        assert(e != null)
+
+        e.typeId() match {
+            case t if EVTS_DISCOVERY_ALL.contains(t) => "di"
+            case t if EVTS_CHECKPOINT.contains(t) => "ch"
+            case t if EVTS_DEPLOYMENT.contains(t) => "de"
+            case t if EVTS_JOB_EXECUTION.contains(t)=> "jo"
+            case t if EVTS_TASK_EXECUTION.contains(t) => "ta"
+            case t if EVTS_CACHE.contains(t) => "ca"
+            case t if EVTS_SWAPSPACE.contains(t) => "sw"
+            case t if EVTS_CACHE_PRELOAD.contains(t) => "cp"
+            case t if EVTS_AUTHENTICATION.contains(t) => "au"
+            case t if EVTS_AUTHORIZATION.contains(t) => "az"
+            case t if EVTS_SECURE_SESSION.contains(t) => "se"
+        }
+    }
+
+    /**
+     * ===Command===
+     * Queries events from specified node filtered by type and/or time frame.
+     *
+     * ===Examples===
+     * <ex>events "-id8=12345678"</ex>
+     * Queries all events from node with '12345678' ID8.
+     *
+     * <ex>events "-id8=12345678 -e=di,ca"</ex>
+     * Queries discovery and cache events from node with '12345678' ID8.
+     *
+     * @param args Command parameters.
+     */
+    def events(args: String) {
+        if (!isConnected)
+            adviseToConnect()
+        else {
+            val argLst = parseArgs(args)
+
+            val typeArg = argValue("e", argLst)
+            val timeArg = argValue("t", argLst)
+
+            val id8 = argValue("id8", argLst)
+            val id = argValue("id", argLst)
+
+            if (!id8.isDefined && !id.isDefined) {
+                scold("Either '-id8' or '-id' must be provided.")
+
+                return
+            }
+
+            if (id8.isDefined && id.isDefined) {
+                scold("Only one of '-id8' or '-id' is allowed.")
+
+                return
+            }
+
+            val node = if (id8.isDefined) {
+                val ns = nodeById8(id8.get)
+
+                if (ns.isEmpty) {
+                    scold("Unknown 'id8' value: " + id8.get)
+
+                    return
+                }
+
+                if (ns.size != 1) {
+                    scold("'id8' resolves to more than one node (use full 'id' instead): " + id8.get)
+
+                    return
+                }
+
+                ns.head
+            }
+            else {
+                val node = try
+                    grid.node(UUID.fromString(id.get))
+                catch {
+                    case _: IllegalArgumentException =>
+                        scold("Invalid node 'id': " + id.get)
+
+                        return
+                }
+
+                if (node == null) {
+                    scold("'id' does not match any node: " + id.get)
+
+                    return
+                }
+
+                node
+            }
+
+            val nid = node.id()
+
+            val tpFilter = try
+                typeFilter(typeArg)
+            catch {
+                case e: Exception =>
+                    scold(e.getMessage)
+
+                    return
+            }
+
+            val tmFilter = try
+                timeFilter(timeArg)
+            catch {
+                case e: Exception =>
+                    scold(e.getMessage)
+
+                    return
+            }
+
+            val evts = try
+                grid.compute(grid.forNode(node)).execute(classOf[VisorNodeEventsCollectorTask],
+                    toTaskArgument(nid, VisorNodeEventsCollectorTaskArg.createEventsArg(tpFilter, tmFilter)))
+            catch {
+                case e: IgniteCheckedException =>
+                    scold(e.getMessage)
+
+                    return
+            }
+
+            if (evts == null || evts.isEmpty) {
+                println("No events found.")
+
+                return
+            }
+
+            val sortedOpt = sort(evts.toList, argValue("s", argLst), hasArgName("r", argLst))
+
+            if (!sortedOpt.isDefined)
+                return
+
+            val sorted = sortedOpt.get
+
+            val cntOpt = argValue("c", argLst)
+
+            var cnt = Int.MaxValue
+
+            if (cntOpt.isDefined)
+                try
+                    cnt = cntOpt.get.toInt
+                catch {
+                    case e: NumberFormatException =>
+                        scold("Invalid count: " + cntOpt.get)
+
+                        return
+                }
+
+            println("Summary:")
+
+            val st = VisorTextTable()
+
+            st += ("Node ID8(@ID)", nodeId8Addr(nid))
+            st += ("Total", sorted.size)
+            st += ("Earliest timestamp", formatDateTime(evts.maxBy(_.timestamp).timestamp))
+            st += ("Oldest timestamp", formatDateTime(evts.minBy(_.timestamp).timestamp))
+
+            st.render()
+
+            nl()
+
+            println("Per-Event Summary:")
+
+            var sum = Map[Int, (String, Int, Long, Long)]()
+
+            evts.foreach(evt => {
+                val info = sum.getOrElse(evt.typeId(), (null, 0, Long.MinValue, Long.MaxValue))
+
+                sum += (evt.typeId -> (
+                    "(" + mnemonic(evt) + ") " + evt.name(),
+                    info._2 + 1,
+                    if (evt.timestamp() > info._3) evt.timestamp() else info._3,
+                    if (evt.timestamp() < info._4) evt.timestamp() else info._4)
+                )
+            })
+
+            val et = VisorTextTable()
+
+            et #= (
+                "Event",
+                "Total",
+                ("Earliest/Oldest", "Timestamp"),
+                ("Rate", "events/sec")
+            )
+
+            sum.values.toList.sortBy(_._2).reverse.foreach(v => {
+                val range = v._3 - v._4
+
+                et += (
+                    v._1,
+                    v._2,
+                    (formatDateTime(v._3), formatDateTime(v._4)),
+                    formatDouble(if (range != 0) (v._2.toDouble * 1000) / range else v._2)
+                )
+            })
+
+            et.render()
+
+            nl()
+
+            if (sorted.size > cnt)
+                println("Top " + cnt + " Events:")
+            else
+                println("All Events:")
+
+            val all = VisorTextTable()
+
+            all.maxCellWidth = 50
+
+            all #= ("Timestamp", "Description")
+
+            sorted.take(cnt).foreach(evt =>
+                all += (formatDateTime(evt.timestamp()), GridUtils.compact(evt.shortDisplay))
+            )
+
+            all.render()
+        }
+    }
+
+    /**
+     * Sort events.
+     *
+     * @param evts Events to sort.
+     * @param arg Command argument.
+     * @param reverse If `true` sorting is reversed.
+     * @return Sorted events.
+     */
+    private def sort(evts: List[_ <: VisorGridEvent], arg: Option[String], reverse: Boolean) = {
+        assert(evts != null)
+
+        if (arg.isEmpty)
+            Some(evts)
+        else
+            arg.get.trim match {
+                case "e" => Some(if (reverse) evts.sortBy(_.name).reverse else evts.sortBy(_.name))
+                case "t" => Some(if (reverse) evts.sortBy(_.timestamp).reverse else evts.sortBy(_.timestamp))
+                case a: String =>
+                    scold("Invalid sorting argument: " + a)
+
+                    None
+            }
+    }
+}
+
+/**
+ * Companion object that does initialization of the command.
+ */
+object VisorEventsCommand {
+    addHelp(
+        name = "events",
+        shortInfo = "Print events from a node.",
+        longInfo = List(
+            "Print events from a node.",
+            " ",
+            "Note that this command depends on GridGain events.",
+            " ",
+            "GridGain events can be individually enabled and disabled and disabled events",
+            "can affect the results produced by this command. Note also that configuration",
+            "of Event Storage SPI that is responsible for temporary storage of generated",
+            "events on each node can also affect the functionality of this command.",
+            " ",
+            "By default - all events are disabled and GridGain stores last 10,000 local",
+            "events on each node. Both of these defaults can be changed in configuration."
+        ),
+        spec = List(
+            "events",
+            "events {-id=<node-id>|-id8=<node-id8>} {-e=<ch,de,di,jo,ta,ca,cp,sw,au>}",
+            "    {-t=<num>s|m|h|d} {-s=e|t} {-r} {-c=<n>}"
+        ),
+        args = List(
+            "-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,cp,sw,au>" -> List(
+                "Comma separated list of event types that should be queried:",
+                "   ch Checkpoint events.",
+                "   de Deployment events.",
+                "   di Discovery events.",
+                "   jo Job execution events.",
+                "   ta Task execution events.",
+                "   ca Cache events.",
+                "   cp Cache pre-loader events.",
+                "   sw Swapspace events.",
+                "   au Authentication events.",
+                "   az Authorization events.",
+                "   se Security session events."
+            ),
+            "-t=<num>s|m|h|d" -> List(
+                "Defines time frame for quering events:",
+                "   =<num>s Queries events fired during last <num> seconds.",
+                "   =<num>m Queries events fired during last <num> minutes.",
+                "   =<num>h Queries events fired during last <num> hours.",
+                "   =<num>d Queries events fired during last <num> days."
+            ),
+            "-s=e|t" -> List(
+                "Defines sorting of queried events:",
+                "   =e Sorted by event type.",
+                "   =t Sorted chronologically.",
+                "Only one '=e' or '=t' can be specified."
+            ),
+            "-r" -> List(
+                "Defines if sorting should be reversed.",
+                "Can be specified only with -s argument."
+            ),
+            "-c=<n>" -> List(
+                "Defines the maximum events count that can be shown.",
+                "Values in summary tables are calculated over the whole list of events."
+            )
+        ),
+        examples = List(
+            "events -id8=12345678" ->
+                "Queries all events from node with '12345678' id8.",
+            "events -id8=@n0" ->
+                "Queries all events from node with id8 taken from 'n0' memory variable.",
+            "events -id8=12345678 -e=di,ca" ->
+                "Queries discovery and cache events from node with '12345678' ID8.",
+            "events" ->
+                "Starts command in interactive mode."
+        ),
+        ref = VisorConsoleCommand(cmd.events, cmd.events)
+    )
+
+    /** Singleton command. */
+    private val cmd = new VisorEventsCommand
+
+    /**
+     * Singleton.
+     */
+    def apply() = cmd
+
+    /**
+     * Implicit converter from visor to commands "pimp".
+     *
+     * @param vs Visor tagging trait.
+     */
+    implicit def fromEvts2Visor(vs: VisorTag) = cmd
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/Packet.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/Packet.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/Packet.scala
new file mode 100644
index 0000000..6bcfca8
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/Packet.scala
@@ -0,0 +1,61 @@
+/*
+ * 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.ignite.visor.commands
+
+/**
+ * ==Overview==
+ * Contains Visor command `gc` implementation.
+ *
+ * ==Help==
+ * {{{
+ * +---------------------------------------------------------------------------+
+ * | gc | Runs garbage collector on remote nodes.                              |
+ * |    | If specific node is provided, garbage collector is run on that node. |
+ * |    | Otherwise, it will be run on all nodes in topology.                  |
+ * +---------------------------------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     gc
+ *     gc "{-id8=<node-id8>|-id=<node-id>} {-c}"
+ * }}}
+ *
+ * ====Arguments====
+ * {{{
+ *     -id8=<node-id8>
+ *         ID8 of the node.
+ *         Note that either '-id8' or '-id' can be specified.
+ *     -id=<node-id>
+ *         ID of the node.
+ *         Note that either '-id8' or '-id' can be specified.
+ *     -c
+ *         Run DGC procedure on all caches.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     gc "-id8=12345678"
+ *         Runs garbage collector on specified node.
+ *     gc
+ *         Runs garbage collector on all nodes in topology.
+ *     gc "-id8=12345678 -c"
+ *         Runs garbage collector and DGC procedure on all caches.
+ * }}}
+ */
+package object gc

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/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
new file mode 100644
index 0000000..850351f
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/gc/VisorGcCommand.scala
@@ -0,0 +1,245 @@
+/*
+ * 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.ignite.visor.commands.gc
+
+import org.apache.ignite.internal.visor.node.VisorNodeGcTask
+
+import org.apache.ignite._
+import org.apache.ignite.cluster.{ClusterGroupEmptyException, ClusterNode}
+
+import java.lang.{Boolean => JavaBoolean}
+import java.util.{UUID, HashSet => JavaHashSet}
+
+import org.apache.ignite.visor.VisorTag
+import org.gridgain.visor._
+import org.apache.ignite.visor.commands.{VisorConsoleCommand, VisorTextTable}
+import visor.visor._
+
+import scala.collection.JavaConversions._
+import scala.language.{implicitConversions, reflectiveCalls}
+import scala.util.control.Breaks._
+
+/**
+ * ==Overview==
+ * Contains Visor command `gc` implementation.
+ *
+ * ==Help==
+ * {{{
+ * +---------------------------------------------------------------------------+
+ * | gc | Runs garbage collector on remote nodes.                              |
+ * |    | If specific node is provided, garbage collector is run on that node. |
+ * |    | Otherwise, it will be run on all nodes in topology.                  |
+ * +---------------------------------------------------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     gc
+ *     gc "{-id8=<node-id8>|-id=<node-id>} {-c}"
+ * }}}
+ *
+ * ====Arguments====
+ * {{{
+ *     -id8=<node-id8>
+ *         ID8 of the node.
+ *         Note that either '-id8' or '-id' can be specified.
+ *     -id=<node-id>
+ *         ID of the node.
+ *         Note that either '-id8' or '-id' can be specified.
+ *     -c
+ *         Run DGC procedure on all caches.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     gc "-id8=12345678"
+ *         Runs garbage collector on specified node.
+ *     gc
+ *         Runs garbage collector on all nodes in topology.
+ *     gc "-id8=12345678 -c"
+ *         Runs garbage collector and DGC procedure on all caches.
+ * }}}
+ */
+class VisorGcCommand {
+    /**
+     * Prints error message and advise.
+     *
+     * @param errMsgs Error messages.
+     */
+    private def scold(errMsgs: Any*) {
+        assert(errMsgs != null)
+
+        nl()
+
+        warn(errMsgs: _*)
+        warn("Type 'help gc' to see how to use this command.")
+    }
+
+    /**
+     * ===Command===
+     * Runs `System.gc()` on specified node or on all nodes in topology.
+     *
+     * ===Examples===
+     * <ex>gc "-id8=12345678"</ex>
+     * Runs `System.gc()` on specified node.
+     *
+     * <ex>gc "-id8=12345678 -c"</ex>
+     * Runs garbage collector and DGC procedure on all caches.
+     */
+    def gc(args: String) = breakable {
+        assert(args != null)
+
+        if (!isConnected)
+            adviseToConnect()
+        else {
+            val argLst = parseArgs(args)
+
+            val id8 = argValue("id8", argLst)
+            val id = argValue("id", argLst)
+            val dgc = hasArgFlag("c", argLst)
+
+            var node: ClusterNode = null
+
+            if (id8.isDefined && id.isDefined)
+                scold("Only one of '-id8' or '-id' is allowed.").^^
+            else if (id8.isDefined) {
+                val ns = nodeById8(id8.get)
+
+                if (ns.isEmpty)
+                    scold("Unknown 'id8' value: " + id8.get).^^
+                else if (ns.size != 1) {
+                    scold("'id8' resolves to more than one node (use full 'id' instead): " + id8.get).^^
+                }
+                else
+                    node = ns.head
+            }
+            else if (id.isDefined)
+                try {
+                    node = grid.node(UUID.fromString(id.get))
+
+                    if (node == null)
+                        scold("'id' does not match any node: " + id.get).^^
+                }
+                catch {
+                    case e: IllegalArgumentException => scold("Invalid node 'id': " + id.get).^^
+                }
+
+            try {
+                val t = VisorTextTable()
+
+                t #= ("Node ID8(@)", "Free Heap Before", "Free Heap After", "Free Heap Delta")
+
+                val prj = grid.forRemotes()
+
+                val nids = prj.nodes().map(_.id())
+
+                val NULL: Void = null
+
+                grid.compute(prj).withNoFailover().execute(classOf[VisorNodeGcTask],
+                    toTaskArgument(nids, NULL)).foreach { case (nid, stat) =>
+                    val roundHb = stat.get1() / (1024L * 1024L)
+                    val roundHa = stat.get2() / (1024L * 1024L)
+
+                    val sign = if (roundHa > roundHb) "+" else ""
+
+                    val deltaPercent = math.round(roundHa * 100d / roundHb - 100)
+
+                    t += (nodeId8(nid), roundHb + "mb", roundHa + "mb", sign + deltaPercent + "%")
+                }
+
+                println("Garbage collector procedure results:")
+
+                t.render()
+            }
+            catch {
+                case e: ClusterGroupEmptyException => scold("Topology is empty.")
+                case e: IgniteCheckedException => scold(e.getMessage)
+            }
+        }
+    }
+
+    /**
+     * ===Command===
+     * Runs `System.gc()` on all nodes in topology.
+     *
+     * ===Examples===
+     * <ex>gc</ex>
+     * Runs `System.gc()` on all nodes in topology.
+     */
+    def gc() {
+        gc("")
+    }
+}
+
+/**
+ * Companion object that does initialization of the command.
+ */
+object VisorGcCommand {
+    addHelp(
+        name = "gc",
+        shortInfo = "Runs GC on remote nodes.",
+        longInfo = List(
+            "Runs garbage collector on remote nodes.",
+            "If specific node is provided, garbage collector is run on that node.",
+            "Otherwise, it will be run on all nodes in topology."
+        ),
+        spec = List(
+            "gc",
+            "gc {-id8=<node-id8>|-id=<node-id>} {-c}"
+        ),
+        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>."
+            ),
+            "-id=<node-id>" -> List(
+                "ID of the node.",
+                "Note that either '-id8' or '-id' can be specified."
+            ),
+            "-c" -> List(
+                "Run DGC procedure on all caches."
+            )
+        ),
+        examples = List(
+            "gc -id8=12345678" ->
+                "Runs garbage collector on specified node.",
+            "gc" ->
+                "Runs garbage collector on all nodes in topology.",
+            "gc -id8=@n0 -c" ->
+                ("Runs garbage collector on specified node with id8 taken from 'n0' memory variable " +
+                "and run DGC procedure on all caches.")
+        ),
+        ref = VisorConsoleCommand(cmd.gc, cmd.gc)
+    )
+
+    /** Singleton command. */
+    private val cmd = new VisorGcCommand
+
+    /**
+     * Singleton.
+     */
+    def apply() = cmd
+
+    /**
+     * Implicit converter from visor to commands "pimp".
+     *
+     * @param vs Visor tagging trait.
+     */
+    implicit def fromGc2Visor(vs: VisorTag) = cmd
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_128x128.png
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_128x128.png b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_128x128.png
new file mode 100644
index 0000000..ba8f954
Binary files /dev/null and b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_128x128.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_48x48.png
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_48x48.png b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_48x48.png
new file mode 100644
index 0000000..ab3ede2
Binary files /dev/null and b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/ggcube_48x48.png differ

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e1c3c8ce/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/Packet.scala
----------------------------------------------------------------------
diff --git a/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/Packet.scala b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/Packet.scala
new file mode 100644
index 0000000..7029a4b
--- /dev/null
+++ b/modules/visor-console/src/main/scala/org/apache/ignite/visor/commands/kill/Packet.scala
@@ -0,0 +1,78 @@
+/*
+ * 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.ignite.visor.commands
+
+/**
+ * ==Overview==
+ * Contains Visor command `kill` implementation.
+ *
+ * ==Help==
+ * {{{
+ * +--------------------------------+
+ * | kill | Kills or restarts node. |
+ * +--------------------------------+
+ * }}}
+ *
+ * ====Specification====
+ * {{{
+ *     kill
+ *     kill "-in|-ih"
+ *     kill "{-r|-k} {-id8=<node-id8>|-id=<node-id>}"
+ * }}}
+ *
+ * ====Arguments====
+ * {{{
+ *     -in
+ *         Run command in interactive mode with ability to
+ *         choose a node to kill or restart.
+ *         Note that either '-in' or '-ih' can be specified.
+ *
+ *         This mode is used by default.
+ *     -ih
+ *         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.
+ *     -r
+ *         Restart node mode.
+ *         Note that either '-r' or '-k' can be specified.
+ *         If no parameters provided - command starts in interactive mode.
+ *     -k
+ *         Kill (stop) node mode.
+ *         Note that either '-r' or '-k' can be specified.
+ *         If no parameters provided - command starts in interactive mode.
+ *     -id8=<node-id8>
+ *         ID8 of the node to kill or restart.
+ *         Note that either '-id8' or '-id' can be specified.
+ *         If no parameters provided - command starts in interactive mode.
+ *     -id=<node-id>
+ *         ID of the node to kill or restart.
+ *         Note that either '-id8' or '-id' can be specified.
+ *         If no parameters provided - command starts in interactive mode.
+ * }}}
+ *
+ * ====Examples====
+ * {{{
+ *     kill
+ *         Starts command in interactive mode.
+ *     kill "-id8=12345678 -r"
+ *         Restart node with '12345678' ID8.
+ *     kill "-k"
+ *         Kill (stop) all nodes.
+ * }}}
+ */
+package object kill


Mime
View raw message