nojava-ipmi-kvm


Namenojava-ipmi-kvm JSON
Version 0.9.3 PyPI version JSON
download
home_pagehttps://github.com/sciapp/nojava-ipmi-kvm
SummaryAccess Java based ipmi kvm consoles without a local Java installation.
upload_time2024-01-26 13:47:11
maintainer
docs_urlNone
authorIngo Meyer
requires_python~=3.5
licenseMIT
keywords ipmi kvm vnc
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # NoJava-IPMI-KVM

## Version incompatibility notice (upgrading from v0.8.1)

Users upgrading from version `v0.8.1` or earlier must rewrite their config files. The previously used ini format was not
flexible enough for adding HTML5 KVM support and was replaced with a [YAML](https://en.wikipedia.org/wiki/YAML) file.

Use the converter script
[`convert_config_file.py`](https://github.com/sciapp/nojava-ipmi-kvm/blob/master/convert_config_file.py)
to convert your old ini config file to the new YAML format.

## Introduction

`nojava-ipmi-kvm` is a tool for running Java-based IPMI-KVM consoles without a local Java installation. It runs a Docker
container in the background, starts a suitable Java Webstart version (from OpenJDK or Oracle) and connects to the
container with [noVNC](https://github.com/novnc/noVNC). By using Docker, Java Webstart is sandboxed automatically and
you don't need to install old Java versions on your Desktop machines.

Starting with version `v0.9.0`, `nojava-ipmi-kvm` also supports HTML5 based kvm viewers.

This project is based on ideas from [solarkennedy/ipmi-kvm-docker](https://github.com/solarkennedy/ipmi-kvm-docker).

## Deploying as a web service

If you would like to access IPMI-KVM consoles with a browser only (without Java plugins and a local installation of
`nojava-impi-kvm`), see [`nojava-ipmi-kvm-server`](https://github.com/sciapp/nojava-ipmi-kvm-server) which encapsulates
`nojava-ipmi-kvm` in a web service.

## Local Installation

The latest version can be obtained from PyPI and runs with Python 3.5+:

```bash
python3 -m pip install nojava-ipmi-kvm
```

[Install Docker](https://www.docker.com/) on your local machine if not done already (or Podman with Docker emulation).

If you run an Arch-based system, you can also install `nojava-ipmi-kvm` from the [AUR](https://aur.archlinux.org/):

```bash
yay -S nojava-ipmi-kvm-docker
```

If you prefer Podman to Docker use the Podman version instead:

```bash
yay -S nojava-ipmi-kvm-podman
```

## Usage

### Configuration file

First, create a file `~/.nojava-ipmi-kvmrc.yaml` and add a template for each kvm host type you want to connect to, for
example:

```yaml
templates:
  kvm-openjdk-7u51:
    skip_login: False
    login_user: ADMIN
    login_endpoint: rpc/WEBSES/create.asp
    allow_insecure_ssl: False
    user_login_attribute_name: WEBVAR_USERNAME
    password_login_attribute_name: WEBVAR_PASSWORD
    send_post_data_as_json: False
    session_cookie_key: SessionCookie
    download_endpoint: Java/jviewer.jnlp
    java_version: 7u51
    format_jnlp: False
```

-   `skip_login`: Skip the login to the KVM host (should be `False` in most cases). If the login is skipped, you can
    omit `login_user`, `login_endpoint`, `user_login_attribute_name` and `password_login_attribute_name`.
-   `login_user`: User to login to the web admin view (default: `ADMIN`)
-   `login_endpoint`: Relative POST url of the login form. Is needed to create a login session.
-   `allow_insecure_ssl`: Allow SSL certificates that cannot be validated when logging in and downloading the KVM
    viewer.
-   `user_login_attribute_name`: Name of the user login field in the login form (use the web inspector of your favorite
    browser to find out the field names).
-   `password_login_attribute_name`: Name of the password field in the login form.
-   `send_post_data_as_json`: Send the login POST request with JSON data as data payload (not needed in most cases)
-   `extra_login_form_fields`: Comma-separated list of key/value pairs which will be sent as additional data on the
    login request. Key and value must be separated by colon (example: `method:login`).
-   `session_cookie_key`: Workaround for web applications that do not set session cookies directly (for example with
    Javascript). If a login attempt does not set a session cookie, the HTTP reply body is scanned for a potential
    session cookie value. If a value is found, it will be stored under the name `session_cookie_key`. In most cases you
    can simply obmit this configuration key. This config value must also be set if `format_jnlp` is set to true.

-   Java-specific configuration keys:
    -   `download_endpoint`: Relative download url of the Java KVM viewer.
    -   `java_version`: Java version that is needed to run Java KVM viewer. Currently, `7u51`, `7u79`, `7u181`, `8u91`,
        `8u242`, `7u80-oracle` and `8u251-oracle` are available (default: `7u181`). The `-oracle` versions are special
        cases which require to build a Docker image yourself because of license restrictions. See [Using Oracle
        Java](#using-oracle-java) for more details.
    -   `format_jnlp`: Replace "{base_url}" and "{session_key}" in the jnlp file (not needed in most cases)
-   HTML5-specific configuration keys:
    -   `html5_endpoint`: Relative url of the HTML5 kvm console.
    -   `rewrites`: List of transformations / patches which must be applied to the HTML5 kvm console code for embedding
        into another web root. Every transformation is described by a dictionary containing the keys `search` (regular
        expression), `replace` and `path_match` (regular expression which specifies which urls will be patched). The
        placeholder `{subdirectory}` contains the new root path.

        Example:

        ```yaml
        rewrites:
        - search: 'var path=""'
          replace: 'var path="{subdirectory}"'
          path_match: "/novnc/include/nav_ui\\.js$"
        ```

Then, add a definition for every single kvm host by reusing the previously defined templates:

```yaml
hosts:
  mykvmhost:
    based_on: kvm-openjdk-7u51
    full_hostname: mykvmhost.org
```

-   `based_on`: Template to use for this host configuration
-   `full_hostname`: Fully qualified name of your KVM host

Template configuration values can be overwritten in the host section.

In addition, you can create a `general` section to configure more general settings, e.g.:

```
general:
  run_docker_with_sudo: False
  x_resolution: 1600x1200
```

-   `run_docker_with_sudo`: Set to True if the `docker` command must be called with `sudo` (needed on Linux if your user
    account is not a member of the `docker` group, defaults to `False`).
-   `x_resolution`: Resolution of the X server and size of the VNC window (default: `1024x768`).
-   `java_docker_image`: Docker image for Java-based kvm consoles (default:
    `sciapp/nojava-ipmi-kvm:v{version}-{java_provider}-{java_major_version}`).
-   `html5_docker_image`: Docker image for Java-based kvm consoles (default: `sciapp/nojava-ipmi-kvm:v{version}-html5`).

Unless you want to use custom docker images, you can omit the config keys `java_docker_image` and `html5_docker_image`.

### Using the command line tool

After configuring, you can call `nojava-ipmi-kvm` from the command line:

```bash
nojava-ipmi-kvm mykvmhost
```

You can start `nojava-ipmi-kvm` multiple times to connect to different machines in parallel. The background Docker
container will be shutdown automatically after to you closed the VNC window (if invoked with the `--use-gui` flag) or
sent `<Ctrl-C>` on the command line.

Options:

```
usage: nojava-ipmi-kvm [-h] [--debug] [-f CONFIG_FILEPATH] [-g]
                       [--print-default-config] [-V]
                       [hostname]

nojava-ipmi-kvm is a utility to access Java based ipmi kvm consoles without a local java installation.

positional arguments:
  hostname              short hostname of the server machine; must be
                        identical with a hostname in `.nojava-ipmi-kvmrc` (for
                        example `mykvmserver`)

optional arguments:
  -h, --help            show this help message and exit
  --debug               print debug messages
  -f CONFIG_FILEPATH, --config-file CONFIG_FILEPATH
                        login user (default: ~/.nojava-ipmi-kvmrc)
  -g, --use-gui         automatically open a PyQt5 browser window. Requires
                        PyQt5 to be installed
  --print-default-config
                        print the default config to stdout and exit
  -V, --version         print the version number and exit
```

## Using Oracle Java

Because of license restrictions we cannot provide pre-built docker images for Oracle Java. However, you can build an
Oracle Java image yourself:

1. Clone this repository:

   ```bash
   git clone git@github.com:sciapp/nojava-ipmi-kvm.git
   ```

2. Visit [the Java download page](https://www.java.com/en/download/manual.jsp) and get the *Linux x64* tar archive of
   Oracle Java version `8u251`. Save it to the `docker` subdirectory of the previously cloned repository as
   `jre-8u251-linux-x64.tar.gz`. If you would like to also use Oracle Java 7, get `jre-7u80-linux-x64.tar.gz` from
   [Oracle's Java archive](https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html) (this
   requires an free Oracle account).

3. Open a terminal and go to the root of the project clone. Run

   ```bash
   git pull
   make build-oracle
   ```

   to build a Docker image with Oracle Java. When you install an updated version of `nojava-ipmi-kvm` repeat these
   commands.

4. Use `java_version: 8u251-oracle` (or `7u80-oracle`) in your `~/.nojava-ipmi-kvmrc.yaml` configuration.

## Command line completion

This repository offers a completion script for bash and zsh (only hostnames currently, no options).

### Bash

Download [the Bash completion
file](https://raw.githubusercontent.com/sciapp/nojava-ipmi-kvm/master/completion/bash/nojava-ipmi-kvm-completion.bash)
and source it in your `.bashrc`, for example by running:

```bash
curl -o .nojava-ipmi-kvm-completion.bash -L https://raw.githubusercontent.com/sciapp/nojava-ipmi-kvm/master/completion/bash/nojava-ipmi-kvm-completion.bash
echo '[ -r "${HOME}/.nojava-ipmi-kvm-completion.bash" ] && source "${HOME}/.nojava-ipmi-kvm-completion.bash"' >> ~/.bashrc
```

### Zsh

You can install the completion script with [zplug](https://github.com/zplug/zplug) or manually.

#### Using zplug

Add `zplug "sciapp/nojava-ipmi-kvm"` to your `.zshrc`, open a new shell and run

```bash
zplug install
```

#### Manual

Clone this repository and source `nojava_ipmi_kvm_completion.plugin.zsh` in your `.zshrc`.

## Acknowledgement

-   Special thanks to @mheuwes for adding the new YAML config file format and adding HTML5 support!

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/sciapp/nojava-ipmi-kvm",
    "name": "nojava-ipmi-kvm",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "~=3.5",
    "maintainer_email": "",
    "keywords": "ipmi,kvm,vnc",
    "author": "Ingo Meyer",
    "author_email": "i.meyer@fz-juelich.de",
    "download_url": "https://files.pythonhosted.org/packages/59/a9/b614a7ce82f8c2acfb70ad0095378ffe91d1f267ae9885b4aaa6db4da834/nojava-ipmi-kvm-0.9.3.tar.gz",
    "platform": null,
    "description": "# NoJava-IPMI-KVM\n\n## Version incompatibility notice (upgrading from v0.8.1)\n\nUsers upgrading from version `v0.8.1` or earlier must rewrite their config files. The previously used ini format was not\nflexible enough for adding HTML5 KVM support and was replaced with a [YAML](https://en.wikipedia.org/wiki/YAML) file.\n\nUse the converter script\n[`convert_config_file.py`](https://github.com/sciapp/nojava-ipmi-kvm/blob/master/convert_config_file.py)\nto convert your old ini config file to the new YAML format.\n\n## Introduction\n\n`nojava-ipmi-kvm` is a tool for running Java-based IPMI-KVM consoles without a local Java installation. It runs a Docker\ncontainer in the background, starts a suitable Java Webstart version (from OpenJDK or Oracle) and connects to the\ncontainer with [noVNC](https://github.com/novnc/noVNC). By using Docker, Java Webstart is sandboxed automatically and\nyou don't need to install old Java versions on your Desktop machines.\n\nStarting with version `v0.9.0`, `nojava-ipmi-kvm` also supports HTML5 based kvm viewers.\n\nThis project is based on ideas from [solarkennedy/ipmi-kvm-docker](https://github.com/solarkennedy/ipmi-kvm-docker).\n\n## Deploying as a web service\n\nIf you would like to access IPMI-KVM consoles with a browser only (without Java plugins and a local installation of\n`nojava-impi-kvm`), see [`nojava-ipmi-kvm-server`](https://github.com/sciapp/nojava-ipmi-kvm-server) which encapsulates\n`nojava-ipmi-kvm` in a web service.\n\n## Local Installation\n\nThe latest version can be obtained from PyPI and runs with Python 3.5+:\n\n```bash\npython3 -m pip install nojava-ipmi-kvm\n```\n\n[Install Docker](https://www.docker.com/) on your local machine if not done already (or Podman with Docker emulation).\n\nIf you run an Arch-based system, you can also install `nojava-ipmi-kvm` from the [AUR](https://aur.archlinux.org/):\n\n```bash\nyay -S nojava-ipmi-kvm-docker\n```\n\nIf you prefer Podman to Docker use the Podman version instead:\n\n```bash\nyay -S nojava-ipmi-kvm-podman\n```\n\n## Usage\n\n### Configuration file\n\nFirst, create a file `~/.nojava-ipmi-kvmrc.yaml` and add a template for each kvm host type you want to connect to, for\nexample:\n\n```yaml\ntemplates:\n  kvm-openjdk-7u51:\n    skip_login: False\n    login_user: ADMIN\n    login_endpoint: rpc/WEBSES/create.asp\n    allow_insecure_ssl: False\n    user_login_attribute_name: WEBVAR_USERNAME\n    password_login_attribute_name: WEBVAR_PASSWORD\n    send_post_data_as_json: False\n    session_cookie_key: SessionCookie\n    download_endpoint: Java/jviewer.jnlp\n    java_version: 7u51\n    format_jnlp: False\n```\n\n-   `skip_login`: Skip the login to the KVM host (should be `False` in most cases). If the login is skipped, you can\n    omit `login_user`, `login_endpoint`, `user_login_attribute_name` and `password_login_attribute_name`.\n-   `login_user`: User to login to the web admin view (default: `ADMIN`)\n-   `login_endpoint`: Relative POST url of the login form. Is needed to create a login session.\n-   `allow_insecure_ssl`: Allow SSL certificates that cannot be validated when logging in and downloading the KVM\n    viewer.\n-   `user_login_attribute_name`: Name of the user login field in the login form (use the web inspector of your favorite\n    browser to find out the field names).\n-   `password_login_attribute_name`: Name of the password field in the login form.\n-   `send_post_data_as_json`: Send the login POST request with JSON data as data payload (not needed in most cases)\n-   `extra_login_form_fields`: Comma-separated list of key/value pairs which will be sent as additional data on the\n    login request. Key and value must be separated by colon (example: `method:login`).\n-   `session_cookie_key`: Workaround for web applications that do not set session cookies directly (for example with\n    Javascript). If a login attempt does not set a session cookie, the HTTP reply body is scanned for a potential\n    session cookie value. If a value is found, it will be stored under the name `session_cookie_key`. In most cases you\n    can simply obmit this configuration key. This config value must also be set if `format_jnlp` is set to true.\n\n-   Java-specific configuration keys:\n    -   `download_endpoint`: Relative download url of the Java KVM viewer.\n    -   `java_version`: Java version that is needed to run Java KVM viewer. Currently, `7u51`, `7u79`, `7u181`, `8u91`,\n        `8u242`, `7u80-oracle` and `8u251-oracle` are available (default: `7u181`). The `-oracle` versions are special\n        cases which require to build a Docker image yourself because of license restrictions. See [Using Oracle\n        Java](#using-oracle-java) for more details.\n    -   `format_jnlp`: Replace \"{base_url}\" and \"{session_key}\" in the jnlp file (not needed in most cases)\n-   HTML5-specific configuration keys:\n    -   `html5_endpoint`: Relative url of the HTML5 kvm console.\n    -   `rewrites`: List of transformations / patches which must be applied to the HTML5 kvm console code for embedding\n        into another web root. Every transformation is described by a dictionary containing the keys `search` (regular\n        expression), `replace` and `path_match` (regular expression which specifies which urls will be patched). The\n        placeholder `{subdirectory}` contains the new root path.\n\n        Example:\n\n        ```yaml\n        rewrites:\n        - search: 'var path=\"\"'\n          replace: 'var path=\"{subdirectory}\"'\n          path_match: \"/novnc/include/nav_ui\\\\.js$\"\n        ```\n\nThen, add a definition for every single kvm host by reusing the previously defined templates:\n\n```yaml\nhosts:\n  mykvmhost:\n    based_on: kvm-openjdk-7u51\n    full_hostname: mykvmhost.org\n```\n\n-   `based_on`: Template to use for this host configuration\n-   `full_hostname`: Fully qualified name of your KVM host\n\nTemplate configuration values can be overwritten in the host section.\n\nIn addition, you can create a `general` section to configure more general settings, e.g.:\n\n```\ngeneral:\n  run_docker_with_sudo: False\n  x_resolution: 1600x1200\n```\n\n-   `run_docker_with_sudo`: Set to True if the `docker` command must be called with `sudo` (needed on Linux if your user\n    account is not a member of the `docker` group, defaults to `False`).\n-   `x_resolution`: Resolution of the X server and size of the VNC window (default: `1024x768`).\n-   `java_docker_image`: Docker image for Java-based kvm consoles (default:\n    `sciapp/nojava-ipmi-kvm:v{version}-{java_provider}-{java_major_version}`).\n-   `html5_docker_image`: Docker image for Java-based kvm consoles (default: `sciapp/nojava-ipmi-kvm:v{version}-html5`).\n\nUnless you want to use custom docker images, you can omit the config keys `java_docker_image` and `html5_docker_image`.\n\n### Using the command line tool\n\nAfter configuring, you can call `nojava-ipmi-kvm` from the command line:\n\n```bash\nnojava-ipmi-kvm mykvmhost\n```\n\nYou can start `nojava-ipmi-kvm` multiple times to connect to different machines in parallel. The background Docker\ncontainer will be shutdown automatically after to you closed the VNC window (if invoked with the `--use-gui` flag) or\nsent `<Ctrl-C>` on the command line.\n\nOptions:\n\n```\nusage: nojava-ipmi-kvm [-h] [--debug] [-f CONFIG_FILEPATH] [-g]\n                       [--print-default-config] [-V]\n                       [hostname]\n\nnojava-ipmi-kvm is a utility to access Java based ipmi kvm consoles without a local java installation.\n\npositional arguments:\n  hostname              short hostname of the server machine; must be\n                        identical with a hostname in `.nojava-ipmi-kvmrc` (for\n                        example `mykvmserver`)\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --debug               print debug messages\n  -f CONFIG_FILEPATH, --config-file CONFIG_FILEPATH\n                        login user (default: ~/.nojava-ipmi-kvmrc)\n  -g, --use-gui         automatically open a PyQt5 browser window. Requires\n                        PyQt5 to be installed\n  --print-default-config\n                        print the default config to stdout and exit\n  -V, --version         print the version number and exit\n```\n\n## Using Oracle Java\n\nBecause of license restrictions we cannot provide pre-built docker images for Oracle Java. However, you can build an\nOracle Java image yourself:\n\n1. Clone this repository:\n\n   ```bash\n   git clone git@github.com:sciapp/nojava-ipmi-kvm.git\n   ```\n\n2. Visit [the Java download page](https://www.java.com/en/download/manual.jsp) and get the *Linux x64* tar archive of\n   Oracle Java version `8u251`. Save it to the `docker` subdirectory of the previously cloned repository as\n   `jre-8u251-linux-x64.tar.gz`. If you would like to also use Oracle Java 7, get `jre-7u80-linux-x64.tar.gz` from\n   [Oracle's Java archive](https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html) (this\n   requires an free Oracle account).\n\n3. Open a terminal and go to the root of the project clone. Run\n\n   ```bash\n   git pull\n   make build-oracle\n   ```\n\n   to build a Docker image with Oracle Java. When you install an updated version of `nojava-ipmi-kvm` repeat these\n   commands.\n\n4. Use `java_version: 8u251-oracle` (or `7u80-oracle`) in your `~/.nojava-ipmi-kvmrc.yaml` configuration.\n\n## Command line completion\n\nThis repository offers a completion script for bash and zsh (only hostnames currently, no options).\n\n### Bash\n\nDownload [the Bash completion\nfile](https://raw.githubusercontent.com/sciapp/nojava-ipmi-kvm/master/completion/bash/nojava-ipmi-kvm-completion.bash)\nand source it in your `.bashrc`, for example by running:\n\n```bash\ncurl -o .nojava-ipmi-kvm-completion.bash -L https://raw.githubusercontent.com/sciapp/nojava-ipmi-kvm/master/completion/bash/nojava-ipmi-kvm-completion.bash\necho '[ -r \"${HOME}/.nojava-ipmi-kvm-completion.bash\" ] && source \"${HOME}/.nojava-ipmi-kvm-completion.bash\"' >> ~/.bashrc\n```\n\n### Zsh\n\nYou can install the completion script with [zplug](https://github.com/zplug/zplug) or manually.\n\n#### Using zplug\n\nAdd `zplug \"sciapp/nojava-ipmi-kvm\"` to your `.zshrc`, open a new shell and run\n\n```bash\nzplug install\n```\n\n#### Manual\n\nClone this repository and source `nojava_ipmi_kvm_completion.plugin.zsh` in your `.zshrc`.\n\n## Acknowledgement\n\n-   Special thanks to @mheuwes for adding the new YAML config file format and adding HTML5 support!\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Access Java based ipmi kvm consoles without a local Java installation.",
    "version": "0.9.3",
    "project_urls": {
        "Homepage": "https://github.com/sciapp/nojava-ipmi-kvm"
    },
    "split_keywords": [
        "ipmi",
        "kvm",
        "vnc"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1b40c29721f0588d54de8a6f30181e8eebb0454604dca0d4f91eb4b9b9525f12",
                "md5": "424a5bd6f7a68057a52067d89bf16071",
                "sha256": "11d944a1cf475c504f4fb9e464824acedf553607349398101cea543e08b6dfd8"
            },
            "downloads": -1,
            "filename": "nojava_ipmi_kvm-0.9.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "424a5bd6f7a68057a52067d89bf16071",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "~=3.5",
            "size": 16319,
            "upload_time": "2024-01-26T13:47:10",
            "upload_time_iso_8601": "2024-01-26T13:47:10.389299Z",
            "url": "https://files.pythonhosted.org/packages/1b/40/c29721f0588d54de8a6f30181e8eebb0454604dca0d4f91eb4b9b9525f12/nojava_ipmi_kvm-0.9.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "59a9b614a7ce82f8c2acfb70ad0095378ffe91d1f267ae9885b4aaa6db4da834",
                "md5": "ec058e73564a81ee447499846896fa1a",
                "sha256": "fa1ab7f4c7a1597b75e2374c32a20a13ecb15d12d396398902f7f81f1d063fb1"
            },
            "downloads": -1,
            "filename": "nojava-ipmi-kvm-0.9.3.tar.gz",
            "has_sig": false,
            "md5_digest": "ec058e73564a81ee447499846896fa1a",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "~=3.5",
            "size": 18088,
            "upload_time": "2024-01-26T13:47:11",
            "upload_time_iso_8601": "2024-01-26T13:47:11.976495Z",
            "url": "https://files.pythonhosted.org/packages/59/a9/b614a7ce82f8c2acfb70ad0095378ffe91d1f267ae9885b4aaa6db4da834/nojava-ipmi-kvm-0.9.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-26 13:47:11",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "sciapp",
    "github_project": "nojava-ipmi-kvm",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "nojava-ipmi-kvm"
}
        
Elapsed time: 0.16970s