Console Shell

General Features

The Equinox OSGi console is based on Apache Felix Gogo, which provides a Unix-like shell for OSGi frameworks. The OSGi console is useful for runtime configuration and management of the framework and bundles deployed within it. It can also be useful for debugging and troubleshooting of OSGi-based applications.

The Equinox console provides:

This guide shows how to configure and use the console in a minimal OSGi runtime.

Starting a Command Line Session

The minimal bundle set needed to start Equinox with the console on the command line is as follows:

All of these bundles are available in the Equinox SDK zip file available from the Equinox Downloads site.

Extract these bundles into a directory, then inside that directory create a configuration/config.ini file with the following content:

    osgi.bundles=\
        org.apache.felix.gogo.runtime,\
        org.apache.felix.gogo.command,\
        org.apache.felix.gogo.shell,\
        org.eclipse.equinox.console

Now this minimal Equinox configuration can be started with a console available on the command line, by passing the -console option, for example:

    $ java -jar org.eclipse.osgi_*.jar -console
    osgi> ss
    "Framework is launched."
    
    id      State       Bundle
    0       ACTIVE      org.eclipse.osgi_3.15.200.v20200214-1600
    1       ACTIVE      org.apache.felix.gogo.runtime_1.1.0.v20180713-1646
    2       ACTIVE      org.apache.felix.gogo.command_1.0.2.v20170914-1324
    3       ACTIVE      org.apache.felix.gogo.shell_1.1.0.v20180713-1646
    4       ACTIVE      org.eclipse.equinox.console_1.4.0.v20190819-1430
    osgi> exit
    Really want to stop Equinox? (y/n; default=y)

Starting a Telnet Session

Starting the console in a Telnet session is enabled by passing a port number with the -console option, for example:

    $ java -jar org.eclipse.osgi_*.jar -console 1234

Once Equinox is started, connect to the Telnet session from another terminal using the port number that was specified above:

    $ telnet localhost 1234
    Trying ::1...
    Connected to localhost.
    Escape character is '^]'.
    osgi> ss
    "Framework is launched."
    
    id      State       Bundle
    0       ACTIVE      org.eclipse.osgi_3.15.200.v20200214-1600
    1       ACTIVE      org.apache.felix.gogo.runtime_1.1.0.v20180713-1646
    2       ACTIVE      org.apache.felix.gogo.command_1.0.2.v20170914-1324
    3       ACTIVE      org.apache.felix.gogo.shell_1.1.0.v20180713-1646
    4       ACTIVE      org.eclipse.equinox.console_1.4.0.v20190819-1430
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection closed by foreign host.

It is possible to set the port in the configuration/config.ini file with the addition of this line:

    osgi.console=1234
    # ... or ...
    osgi.console=localhost:1234

The osgi.console property specifies the port (and optionally the hostname) on which the console should listen for Telnet connections without needing to pass the -console option at all, but if -console is passed it will override any setting present in the configuration/config.ini file.

Starting an SSH Session With JAAS Authentication

To start a console session in an SSH session, a few more bundles are needed:

All of these bundles are available in the Equinox SDK zip file available from the Equinox Downloads site.

Extract these bundles into a directory, then inside that directory create a configuration/config.ini file with the following content:

    osgi.bundles=\
        org.apache.felix.gogo.runtime,\
        org.apache.felix.gogo.command,\
        org.apache.felix.gogo.shell,\
        org.apache.sshd.osgi,\
        org.eclipse.equinox.console,\
        org.eclipse.equinox.console.jaas.fragment,\
        org.eclipse.equinox.console.ssh@start,\
        org.slf4j.api
    osgi.console.ssh=127.0.0.1:1234
    osgi.console.ssh.useDefaultSecureStorage=true

Equinox uses JAAS to authenticate SSH sessions, the default login provider of which must be configured by creating a JAAS configuration file, for example by creating a file configuration/console.auth.config with the following content:

    equinox_console {
        org.eclipse.equinox.console.jaas.SecureStorageLoginModule REQUIRED;
    };

Then when starting Equinox, it must be told where the JAAS configuration is by setting the java.security.auth.login.config system property. The default JAAS login provider stores its credentials in a one-way encrypted store file that must be specified with the org.eclipse.equinox.console.jaas.file system property:

    $ java -Dssh.server.keystore=configuration/hostkey.ser \
           -Dorg.eclipse.equinox.console.jaas.file=configuration/store \
           -Djava.security.auth.login.config=configuration/console.auth.config \
           -jar org.eclipse.osgi_*.jar

The default JAAS login provider dynamically creates one default user equinox with password equinox. After logging in with these credentials for the first time, the user will be prompted to create a new account and the default account will be removed.

Once Equinox is started, connect to the SSH session from another terminal using the hostname and port specified in the configuration/config.ini file:

    $ ssh -p 1234 equinox@127.0.0.1
    The authenticity of host '[127.0.0.1]:1234 ([127.0.0.1]:1234)' can't be established.
    RSA key fingerprint is SHA256:7x3eOsDRM5lyL5vRsVREy8hIawIfqRiZ7CBnk6GkfRA.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '[127.0.0.1]:1234' (RSA) to the list of known hosts.
    Password authentication
    Password: 
    Currently the default user is the only one; since it will be deleted after first login, create a new user:
    username: mbooth
    password: 
    Confirm password: 
    roles: admin
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection to 127.0.0.1 closed.

The password must be at least 8 symbols long and the username may contain alphanumerical characters, underscores and dots. On subsequent connections the user will be required to supply the newly created credentials:

    $ ssh -p 1234 mbooth@127.0.0.1
    Password authentication
    Password: 
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection to 127.0.0.1 closed.

Once logged in there are various commands for administering users. Type help at the OSGi console prompt to explore commands to perform the following functions:

Custom JAAS Authentication Login Providers

Only authentication is implemented in the default JAAS login provider so by default all authenticated users have similar rights. Roles exist to allow authorization to be added in custom JAAS login providers.

A custom JAAS login provider can be used by creating a bundle fragment that extends the org.apache.sshd.osgi bundle. This fragment is used to provide or import the package of the custom login provider. This is necessary for the SSH system to be able to load the provider class.

If a custom JAAS login provider is used, then the osgi.console.ssh.useDefaultSecureStorage property must not be set in the configuration/config.ini at all and the custom login provider must be specified in the configuration/console.auth.config file instead of the default entry there.

Starting an SSH Session With Public Key Authentication

It's common to want to use public key authentication with SSH and it is possible to configure Equinox to do that instead of using JAAS authentication. First an SSH key-pair should be created as normal and then a file created that contains the list of authorized keys that Equinox should consult when users attempt to connect:

    $ ssh-keygen -f ~/.ssh/equinox
    Generating public/private rsa key pair.
    Enter passphrase (empty for no passphrase): 
    Enter same passphrase again: 
    Your identification has been saved in /home/mbooth/.ssh/equinox
    Your public key has been saved in /home/mbooth/.ssh/equinox.pub
    The key fingerprint is:
    SHA256:0k7MSbLLzhhzI7Gw6oSYEx8Fv5UpNHMPTdOUDj8rplQ mbooth@thinkpad-p50
    The key's randomart image is:
    +---[RSA 3072]----+
    |  . + oooo..     |
    |   + + =o.o      |
    |    + = o+       |
    |   . + BE.+      |
    |. o o o.S  o     |
    |o+ + +.=o .      |
    |=.o =.=o..       |
    |.o   O..         |
    |o.  . o          |
    +----[SHA256]-----+
    
    $ cat ~/.ssh/equinox.pub > configuration/equinox_authorized_keys

Next the following line must be removed from the configuration/config.ini file:

    # Remove this line to use public key authentication
    # Must only be present when using the default JAAS login provider
    osgi.console.ssh.useDefaultSecureStorage=true

Now when starting Equinox, instead of telling it about the JAAS configuration, it must be told about the authorized keys file by setting the ssh.server.authorized_keys system property:

    $ java -Dssh.server.keystore=configuration/hostkey.ser \
           -Dssh.server.authorized_keys=configuration/equinox_authorized_keys \
           -jar org.eclipse.osgi_*.jar

And that allows users to use their SSH keys instead of a username/password pair when connecting to the SSH console session:

    $ ssh -i ~/.ssh/equinox -p 1234 localhost
    The authenticity of host '[localhost]:1234 ([127.0.0.1]:1234)' can't be established.
    RSA key fingerprint is SHA256:m2JKy2fRZA1aqvxHBBe+Awsgk98ryI29fH03Rg7jeHw.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '[localhost]:1234' (RSA) to the list of known hosts.
    osgi> disconnect
    Disconnect from console? (y/n; default=y) 
    Connection to localhost closed.

The authorized keys file given to Equinox will be read every time a connection is made, which allows adding and removing of keys dynamically at runtime.

Custom Public Key Authentication

Equinox also supports customizing the public key authentication mechanism. If no specific authorized keys file is configured via system property then the OSGi service registry will be searched for available authenticators. To enable this feature set the ssh.custom.publickeys.auth system property to true.

Starting Telnet and SSH Sessions Together

It is possible to start Equinox console sessions over both Telnet and SSH simultaneously. For this, both the osgi.console and osgi.console.ssh properties must be specified in the configuration/config.ini file:

    # Telnet session
    osgi.console=<hostname>:<port>
    # SSH session
    osgi.console.ssh=<hostname>:<port>

These properties specify the port on which to listen and the hostname (or IP address) to which it binds for incoming connections.

For both properties, the hostname (or IP address) is optional and may be omitted. If the hostname is omitted, then localhost is assumed. If the hostname is the same for both properties, or both hostnames are omitted then the SSH session must have a different port number to the Telnet session.

Using the Configuration Admin Service

It is possible to configure Telnet and SSH console sessions through the Configuration Admin Service instead of using the osgi.console and osgi.console.ssh properties. This is helpful in more complex scenarios, for example when you want to run different instances of the console in different subsystems of the framework. In this case if the port is configured through a system property, the same value is used for all console instances and only one will be able to bind to the socket.

To enable this feature, the Configuration Admin bundle and it's dependencies must be added to the Equinox instance:

All of these bundles are available in the Equinox SDK zip file available from the Equinox Downloads site.

And then in the configuration/config.ini file, the osgi.console.useConfigAdmin property must be used in place of the usual configuration properties:

    # Remove these properties:
    #osgi.console=<hostname>:<port>
    #osgi.console.ssh=<hostname>:<port>

    # Use the Config Admin Service instead:
    osgi.console.useConfigAdmin=true

Now a custom bundle must be written that uses the Configuration Admin Service to configure Telnet and SSH console sessions. The Persistent Identity (PID) for the Telnet configuration is osgi.console.telnet and for the SSH configuration is osgi.console.ssh. Both configurations have the following properties, all expecting values of type String:

The enabled property determines if the Telnet or SSH session is to be started at all. If the value is true, it is started. If the value is false, or the property enabled is absent, the Telnet or SSH session is not started.

Console Command Usage

The Equinox console works similarly to Unix-style shells. Multiple commands can be sent when separated by a semi-colon and the output of commands may be piped to the input of other commands. For example:

    osgi> ss | grep slf4j
    8       ACTIVE      org.slf4j.api_1.7.2.v20121108-1250
    true
    osgi> stop 8 ; start 8

IO redirection can be simulated with the cat and tac commands. For example:

    osgi> ss | tac out.txt
    osgi> cat out.txt | grep slf4j
    8       ACTIVE      org.slf4j.api_1.7.2.v20121108-1250
    true

The console also has standard command line editing features such as:

However some of these editing features are only supported when using the console via a Telnet or SSH session.

Command Scopes

Equinox console commands have the notion of command scope. The scope is a kind of namespace that can be used, for example, to differentiate between commands with the same name, but provided by different providers.

The scope is a prefix of the command name, separated from it by a colon. When writing the command in the console, specifying the scope is optional: A command may be written as command_name or scope:command_name. If the scope is not specified, then the command with this name from the default scope is used. If there is no such command in the default scope, all scopes are searched.

If there is more than one command with the specified name in different, non-default scopes, it is not guaranteed which one will be actually executed. Therefore, if there are commands with the same name but in different scopes, the scope prefix must be specified explicitly with the command name to ensure that exactly the desired command is executed.

The Equinox console is now based on Apache Felix Gogo, which has a different way of implementing console commands than the traditional Equinox way. Equinox adapts these legacy commands for the Gogo-based shell and makes them available in the equinox scope. For compatibility, the default scope is the equinox scope.

Getting Help for Commands

Typing help (or man) at the OSGi console prompt with no arguments, the help for all available commands is displayed. To limit the output to commands from a specific scope, the -scope <scope_name> parameter can be passed to the help command:

    osgi> help -scope equinox

    close - shutdown and exit
       scope: equinox

    diag - Displays unsatisfied constraints for the specified bundle(s)
       scope: equinox
       parameters:
          Bundle[]   IDs of bundle(s), for which to display unsatisfied constraints

    ...etc...

The help text for a specific command can be shown by passing a command_name or scope:command_name to the help command. If the scope is not specified, then the help text is shown for the command from the default scope if it exists:

    osgi> help headers

    headers - print bundle headers
       scope: equinox
       parameters:
          Bundle[]   bundles to print headers for

    osgi> help felix:headers

    headers - display bundle headers
       scope: felix
       parameters:
          Bundle[]   target bundles

The default help command provided by the Apache Felix Gogo shell does not provide help for the legacy Equinox commands, which are adapted by the Equinox console for the Gogo shell. For this reason the Equinox console provides its own help command in the equinox scope that delegates to the default help command whilst also providing help for legacy commands.

Closing Console Sessions

When using the Equinox console standalone on the command line, the exit command can be used to terminate Equinox and return to the system command prompt.

For both Telnet and SSH sessions, the session can be closed without terminating Equinox with the disconnect command.

Implementing Custom Console Commands

Traditionally in Equinox commands are provided by a class implementing the org.eclipse.osgi.framework.console.CommandProvider interface. The Equinox console provides an adapter from this legacy type of command to the new type of command used in Gogo but it is preferred that new commands are implemented as Gogo commands directly.

Commands for Apache Felix Gogo are plain old Java object (POJO) classes with all the commands implemented as public methods. The methods may have arbitrary arguments. These classes are registered as services, with two special properties:

Gogo commands also have the notion of converters and formatters.

A converter is a class which converts the arguments passed at the OSGi console prompt, to the actual arguments that the command accepts. For example, the command may have one argument of type Bundle. A converter might accept a long integer and finds the bundle with this ID. Then the command may be called with the ID of the bundle as an argument, the converter will convert it to the corresponding Bundle object and the command method will be called with this object as an argument.

A formatter is a class which displays a result returned by a command method.

For more information on Gogo commands, see the Gogo documentation.

Implementing Custom Tab Completion

The Equinox console provides tab completion and allows implementors to provide their own custom completion providers. This feature is available only when connecting through a Telnet or SSH session. Completion is available for:

When the tab key is typed, all possible candidates for completion for the current word are searched. If there is only one possible completion, the current word is automatically completed. If there is more than one option, all are displayed. The user can then cycle through the possible completions by hitting tab multiple times, until the desired completion candidate is selected.

If longest common prefix of all available completion candidates is longer than the current word, then the current word is completed automatically to this prefix before choosing the final completion. For example, if the following completions are available for the word bun:

Then the current word is completed automatically to bundle and the user can continue typing normally or, by hitting tab again, they can cycle through the possible completions.

A custom completer should implement the org.eclipse.equinox.console.common.Completer interface provided by the Equinox console bundle. It has the single method getCandidates, which take as parameters the whole command line and the current cursor position within it, and returns a map of completion candidates to positions in the command line at which the completion begins.