//
// Licensed 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.
//

=== Instances

A instance is a complete new Apache Karaf runtime, isolated from the other ones.

The purpose is to easily create and manage a new Apache Karaf runtime without installing a complete distribution.

A instance is a new instance that you can launch separately from the root one, and deploy applications into. It means that each instance is run on a different JVM.

A instance does not contain a full copy of the Apache Karaf distribution, but only a set of the configuration files and data folder which contains all the runtime information, logs and temporary files.

==== Using the instance commands

The *instance* commands allow you to create and manage instances.

===== Creating instances

You create a new runtime instance by typing [`instance:create`|/commands/instance-create] in the Karaf console.

As shown in the following example, `instance:create` causes the runtime to create a new runtime installation in the active runtime's `instances/[name]} directory.  The new instance is a new Karaf instance and is assigned an SSH port number based on an incremental count starting at 8101 and a RMI registry port number based on an incremental count starting at 1099.

----
karaf@root()> instance:create test
----

The new instance is a fresh Apache Karaf instance. It uses the same default configuration files, as when you install a fresh Karaf distribution.

You can enable the verbose mode for the `instance:create` command using the `-v` option:

----
karaf@root()> instance:create -v test
Creating new instance on SSH port 8103 and registry port 1101 / RMI server port 44446 at: /opt/karaf/instances/test
Creating dir: /opt/karaf/instances/test/bin
Creating dir: /opt/karaf/instances/test/etc
Creating dir: /opt/karaf/instances/test/system
Creating dir: /opt/karaf/instances/test/deploy
Creating dir: /opt/karaf/instances/test/data
Creating file: /opt/karaf/instances/test/etc/config.properties
Creating file: /opt/karaf/instances/test/etc/jre.properties
Creating file: /opt/karaf/instances/test/etc/custom.properties
Creating file: /opt/karaf/instances/test/etc/java.util.logging.properties
Creating file: /opt/karaf/instances/test/etc/org.apache.felix.fileinstall-deploy.cfg
Creating file: /opt/karaf/instances/test/etc/org.apache.karaf.features.obr.cfg
Creating file: /opt/karaf/instances/test/etc/org.apache.karaf.features.repos.cfg
Creating file: /opt/karaf/instances/test/etc/org.apache.karaf.log.cfg
Creating file: /opt/karaf/instances/test/etc/org.ops4j.pax.logging.cfg
Creating file: /opt/karaf/instances/test/etc/org.ops4j.pax.url.mvn.cfg
Creating file: /opt/karaf/instances/test/etc/users.properties
Creating file: /opt/karaf/instances/test/etc/keys.properties
Creating file: /opt/karaf/instances/test/etc/org.apache.karaf.features.cfg
Creating file: /opt/karaf/instances/test/etc/system.properties
Creating file: /opt/karaf/instances/test/etc/org.apache.karaf.shell.cfg
Creating file: /opt/karaf/instances/test/etc/org.apache.karaf.management.cfg
Creating file: /opt/karaf/instances/test/bin/karaf
Creating file: /opt/karaf/instances/test/bin/start
Creating file: /opt/karaf/instances/test/bin/stop
----

You can manually configure the different ports, the location of the instance, the Apache Karaf features URLs using different options of the `instance:create` command.
You can have details about these options using the `--help` option.

===== Cloning an instance

Instead of creating a fresh instance, you can clone an existing instance using `instance:clone`.

The `instance:clone` command reuse the files from the source instance:

----
karaf@root()> instance:clone root test
----

You can have details about the cloning options using the `--help` option.

===== Changing the instance location

By default, the new instances storage is in the `KARAF_HOME/instance` directory.
You find a directory with the name of the instance storing the different instance files.

You can change the location of the instance using the `-l` option to the `instance:create` and `instance:clone` commands:

----
karaf@root()> instance:create -v -l /tmp/test test
Creating new instance on SSH port 8102 and registry port 1100 / RMI server port 44445 at: /tmp/test
Creating dir: /tmp/test/bin
Creating dir: /tmp/test/etc
Creating dir: /tmp/test/system
Creating dir: /tmp/test/deploy
Creating dir: /tmp/test/data
Creating file: /tmp/test/etc/config.properties
Creating file: /tmp/test/etc/jre.properties
Creating file: /tmp/test/etc/custom.properties
Creating file: /tmp/test/etc/java.util.logging.properties
Creating file: /tmp/test/etc/org.apache.felix.fileinstall-deploy.cfg
Creating file: /tmp/test/etc/org.apache.karaf.features.obr.cfg
Creating file: /tmp/test/etc/org.apache.karaf.features.repos.cfg
Creating file: /tmp/test/etc/org.apache.karaf.log.cfg
Creating file: /tmp/test/etc/org.ops4j.pax.logging.cfg
Creating file: /tmp/test/etc/org.ops4j.pax.url.mvn.cfg
Creating file: /tmp/test/etc/users.properties
Creating file: /tmp/test/etc/keys.properties
Creating file: /tmp/test/etc/org.apache.karaf.features.cfg
Creating file: /tmp/test/etc/system.properties
Creating file: /tmp/test/etc/org.apache.karaf.shell.cfg
Creating file: /tmp/test/etc/org.apache.karaf.management.cfg
Creating file: /tmp/test/bin/karaf
Creating file: /tmp/test/bin/start
Creating file: /tmp/test/bin/stop
----

Careful, it's not possible to change the location of an instance once it has been created.

[NOTE]
====
`instance:destroy` will remove the instance location for you. You don't have to remove the instance location "by hand".
====

===== Changing instance ports

You can change the SSH port number assigned to an instance using the `instance:ssh-port-change` command:

----
karaf@root()> instance:ssh-port-change test 8104
----

where test is the instance name and 8104 is the new SSH port number to use for the test instance.

You can change the RMI Registry port number (used by JMX) of an instance using the `instance:rmi-registry-port-change` command:

----
karaf@root()> instance:rmi-registry-port-change test 1102
----

where test is the instance name and 1102 is the new RMI Registry port number to use for the test instance.

You can also change the RMI Server port number (used by JMX too) of an instance using the `instance:rmi-server-port-change` command:

----
karaf@root()> instance:rmi-server-port-change test 44447
----

where test is the instance name and 44447 is the new RMI Server port number to use for the test instance.

[NOTE]
====
The instance has to be stopped to be able to change the port numbers.
====

===== Starting instances

New instances are created in a stopped state.

To start an instance, you can use the `instance:start` command:

----
karaf@root()> instance:start test
----

where test is the instance name.

===== Listing instances

To list the instances and their current status, you can use the `instance:list` command:

----
karaf@root()> instance:list
SSH Port | RMI Registry | RMI Server | State   | PID   | Name
-------------------------------------------------------------
    8101 |         1099 |      44444 | Started | 19652 | root
    8104 |         1101 |      44446 | Stopped | 0     | test
----

An instance can be in the following status:

- Stopped: the instance is stopped.
- Starting: the instance is starting.
- Started: the instance is up and running. You can connect and use it.

===== Status of an instance

You can get directly the status of a given instance using the `instance:status` command:

----
karaf@root()> instance:status test
Started
----

where test is the instance name.

===== Connecting to an instance

You can connect to a running instance directly from the root one using the `instance:connect` command:

----
karaf@root()> instance:connect test
----

where 'test' is the instance name where to connect to.

By default, this command will use the same username used on the root instance, and the password will be prompted.

You can use a different username using the `-u` or `--username` option. You can also provide the password using the
`-p` or `--password` option.

If you don't provide any argument, you will logon on the instance:

----
karaf@test()>
----

Note the name of instance in the shell prompt (@test).

You can logoff from the instance and return back to the root instance using the `logout` command or CTRL-D key binding:

----
karaf@test()> logout
karaf@root()>
----

The `instance:connect` command accepts shell commands as argument. It allows you to directly execute commands or scripts on the instance:

----
karaf@root()> instance:connect test feature:list
Name                          | Version         | Installed | Repository                | Description
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
standard                      | 4.0.0           | x         | standard-4.0.0            | Karaf standard feature
aries-annotation              | 4.0.0           |           | standard-4.0.0            | Aries Annotations
wrapper                       | 4.0.0           |           | standard-4.0.0            | Provide OS integration
service-wrapper               | 4.0.0           |           | standard-4.0.0            | Provide OS integration (alias to wrapper feature)
obr                           | 4.0.0           |           | standard-4.0.0            | Provide OSGi Bundle Repository (OBR) support
config                        | 4.0.0           | x         | standard-4.0.0            | Provide OSGi ConfigAdmin support
region                        | 4.0.0           | x         | standard-4.0.0            | Provide Region Support
...
----

===== Stop an instance

To stop an instance, you can connect to the instance (using `instance:connect`) and execute the `system:shutdown`
command.

You can also use the `instance:stop` command:

----
karaf@root()> instance:stop test
----

where test is the instance name.

The instance will go to the "Stopped" state.

===== Destroy an instance

You can completely delete a stopped instance using the `instance:destroy` command:

----
karaf@root()> instance:destroy test
----

where test is the instance name.

[NOTE]
====
The `instance:destroy` deletes the instance store (the location where the instance files are stored).
====

===== Package an instance
You can create a .zip file to save all the files of an instance (including the root instance) by executing `instance:package` command. You must provide
an instance name and the target path. The target path can be relative to the instance home directory
or an absolute path in your filesystem. The command will output filenames of the compressed files (just like zip Unix command).
----
karaf@root()> instance:package root root.zip    
RELEASE-NOTES.md
lock
NOTICE
deploy/README
BUILDING.md
etc/org.apache.karaf.command.acl.config.cfg
...
Archive available at root.zip
----


===== Rename an instance

You can change the name of a stopped instance using the `instance:rename` command:

----
karaf@root()> instance:rename test newTest
----

where test is the current instance name, and newTest the new instance name.

==== Instance script

The `instance:*` commands require the root instance running.

But, you can also administrate directly instances without the root instance, using the `bin/instance` Unix script
(or `bin/instance.bat` script on Windows).

You find the same actions that you can do with the `instance:*` commands in the `instance[.bat]` script:

----
bin/instance
Available commands:
  clone - Clones an existing container instance.
  create - Creates a new container instance.
  destroy - Destroys an existing container instance.
  list - Lists all existing container instances.
  opts-change - Changes the Java options of an existing container instance.
  rename - Rename an existing container instance.
  rmi-registry-port-change - Changes the RMI registry port (used by management layer) of an existing container instance.
  rmi-server-port-change - Changes the RMI server port (used by management layer) of an existing instance.
  ssh-port-change - Changes the secure shell port of an existing container instance.
  start - Start an existing container instance.
  status - Check the current status of an instance.
  stop - Stop an existing container instance.
Type 'command --help' for more help on the specified command.
----

For instance, to list all the instances, you can use the `instance` script with the `list` command:

----
bin/instance list
SSH Port | RMI Registry | RMI Server | State   | PID | Name
-----------------------------------------------------------
    8101 |         1099 |      44444 | Stopped | 0   | root
    8102 |         1100 |      44445 | Stopped | 0   | test
----

It's exactly the same as executing `instance:list` in the root instance.

You can obtain details about commands options and arguments using the `--help` option. For instance:

----
bin/instance rename --help
DESCRIPTION
        instance:rename

        Rename an existing container instance.

SYNTAX
        instance:rename [options] name new-name

ARGUMENTS
        name
                The name of the container instance to rename
        new-name
                The new name of the container instance

OPTIONS
        --help
                Display this help message
        -v, --verbose
                Display actions performed by the command (disabled by default)

----

==== JMX InstanceMBean

On the JMX layer, you have a MBean dedicated to the management of the instances: the InstanceMBean.

The ObjectName to use is `org.apache.karaf:type=instance,name=*`.

===== Attributes

The `Instances` attribute is a tabular data attribute providing details about the instances:

* `Is Root` (boolean): if true, the instance is the root instance, false else.
* `JavaOpts` (string): it contains the JVM arguments used by the instance.
* `Location` (string): it's the path to the instance storage.
* `Name` (string): it's the name of the instance.
* `Pid` (long): it's the current system process ID (PID) of the instance process.
* `RMI Registry Port` (int): it's the port number of the instance RMI Registry (JMX).
* `RMI Server Port` (int): it's the port number of the instance RMI Server (JMX).
* `SSH Port` (int): it's the port number of the instance SSH Server.
* `State` (string): it's the current status of the instance (Stopped, Starting, Started).

===== Operations

The InstanceMBean provides the following operations, corresponding to the previous `instance:*` commands:

* `createInstance(instanceName, sshPort, rmiRegistryPort, rmiServerPort, location, javaOpts, features, featuresUrls)`: create a new instance.
* `changeSshPort(instanceName, port)`: change the SSH port of an instance.
* `changeRmiServerPort(instanceName, port)`: change the RMI server port of an instance.
* `changeRmiRegistry(instanceName, port)`: change the RMI registry port of an instance.
* `changeJavaOpts(instanceName, javaOpts)`: change the Java options of an instance.
* `destroyInstance(instanceName)`: destroy an instance.
* `startInstance(instanceName)`: start an instance.
* `startInstance(instanceName, options)`: start an instance with the given Java options.
* `startInstance(instanceName, options, wait, debug)`: start an instance with the given Java options.
 If wait is true, this operation is waiting for the instance is in "Started" state. If debug is true, the instance is started in debug mode.
* `stopInstance(instanceName)`: stop an instance.
* `renameInstance(instanceName, newInstanceName)`: rename an instance.
* `renameInstance(instanceName, newInstanceName, verbose)`: rename an instance. If verbose is true, this operation provides details in the log.
* `cloneInstance(instanceName, cloneName, sshPort, rmiRegistryPort, rmiServerPort, location, javaOpts)`: clone an existing instance.
