chore(ExApp): migrate and split AppAPI documentation to relevant manuals
Signed-off-by: Edward Ly <contact@edward.ly>
19
admin_manual/exapps_management/Concepts.rst
Normal file
@@ -0,0 +1,19 @@
|
||||
Concepts
|
||||
========
|
||||
|
||||
API Access Control Mechanism
|
||||
----------------------------
|
||||
|
||||
Each application defines list of API groups it intends to access.
|
||||
|
||||
This system easily allows you to increase the level of trust in applications.
|
||||
Even prior to installation, it's possible to ascertain the API groups to which an application will gain access.
|
||||
|
||||
Extensible Deployment
|
||||
---------------------
|
||||
|
||||
The system should support the expansion and integration of new deployment methods, avoiding any tight coupling with a specific deployment type.
|
||||
Applications should be capable of indicating the deployment methods they can accommodate.
|
||||
|
||||
Given the evolving landscape of new technologies and the potential emergence of more intricate or simplified deployment options,
|
||||
the system is architected to seamlessly embrace the integration of novel deployment modes.
|
||||
135
admin_manual/exapps_management/CreationOfDeployDaemon.rst
Normal file
@@ -0,0 +1,135 @@
|
||||
.. _create-deploy-daemon:
|
||||
|
||||
Creation of Deploy Daemon
|
||||
=========================
|
||||
|
||||
The Deploy Daemon (DaemonConfig) is used to orchestrate the deployment of ExApps.
|
||||
|
||||
.. note::
|
||||
|
||||
Currently only ``docker-install`` and ``manual-install`` deployment methods are supported.
|
||||
|
||||
The recommended daemon configuration is using `AppAPI Docker Socket Proxy <https://github.com/cloud-py-api/docker-socket-proxy>`_.
|
||||
|
||||
.. image:: ./img/app_api_3.png
|
||||
|
||||
|
||||
You can choose one of the basic configuration templates and adjust to your needs.
|
||||
|
||||
.. note:: We highly recommend to use UI to create Deploy Daemons.
|
||||
|
||||
Register Deploy daemon form
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. ``Name``: unique name of the Deploy daemon
|
||||
2. ``Display name``: the name that will be displayed in the UI
|
||||
3. ``Deployment method``: by default you will need to choose ``docker_install``, ``manual_install`` is for development or custom use case of manual ExApp installation
|
||||
4. ``Daemon Host``: hostname/IP address + port of the Deploy daemon
|
||||
5. ``Nextcloud URL``: autofilled with current domain, you might need to change the protocol to http/https depending on your setup
|
||||
6. ``Set as default daemon``: check if you want set new Deploy daemon as default
|
||||
7. ``Enable https``: check if your Deploy daemon (Docker Socket Proxy) is configured with TLS
|
||||
8. Deploy Config:
|
||||
9. ``Network``: Docker network name, depends on your networking setup, enforces to "host" if "Enable https" is checked
|
||||
10. ``HaProxy password``: password for Docker Socket Proxy, if it is configured with TLS
|
||||
11. ``Compute Device``: CPU, CUDA or ROCm, depending on your hardware config on Deploy daemon host machine
|
||||
12. ``Add additional option`` (see :ref:`additional_options_list`): setup additional KEY + VALUE deploy config options
|
||||
|
||||
.. note::
|
||||
|
||||
For remote DSP setup, it should expose the ports on the host.
|
||||
|
||||
|
||||
.. _create-deploy-daemon-cli:
|
||||
|
||||
OCC CLI
|
||||
^^^^^^^
|
||||
|
||||
There are a few commands to manage Deploy Daemons:
|
||||
|
||||
1. Register ``occ app_api:daemon:register``
|
||||
2. Unregister ``occ app_api:daemon:unregister``
|
||||
3. List registered daemons ``occ app_api:daemon:list``
|
||||
|
||||
Register
|
||||
--------
|
||||
|
||||
Register Deploy Daemon (DaemonConfig).
|
||||
|
||||
Command: ``app_api:daemon:register [--net NET] [--haproxy_password HAPROXY_PASSWORD] [--compute_device COMPUTE_DEVICE] [--set-default] [--] <name> <display-name> <accepts-deploy-id> <protocol> <host> <nextcloud_url>``
|
||||
|
||||
Arguments
|
||||
*********
|
||||
|
||||
* ``name`` - unique name of the daemon (e.g. ``docker_local_sock``)
|
||||
* ``display-name`` - name of the daemon (e.g. ``My Local Docker``, will be displayed in the UI)
|
||||
* ``accepts-deploy-id`` - type of deployment (``docker-install`` or ``manual-install``)
|
||||
* ``host`` - **path to docker-socket** or the Docker Socket Proxy: ``address:port``
|
||||
* ``protocol`` - protocol used to communicate with the Daemon/ExApps (``http`` or ``https``)
|
||||
* ``nextcloud_url`` - Nextcloud URL, Daemon config required option (e.g. ``https://nextcloud.local``)
|
||||
|
||||
Options
|
||||
*******
|
||||
|
||||
* ``--net [network-name]`` - ``[required]`` network name to bind docker container to (default: ``host``)
|
||||
* ``--haproxy_password HAPROXY_PASSWORD`` - ``[optional]`` password for AppAPI Docker Socket Proxy
|
||||
* ``--compute_device GPU`` - ``[optional]`` GPU device to expose to the daemon (e.g. ``cpu|cuda|rocm``, default: ``cpu``)
|
||||
* ``--set-default`` - ``[optional]`` set created daemon as default for ExApps installation
|
||||
|
||||
DeployConfig
|
||||
************
|
||||
|
||||
DeployConfig is a set of additional options in Daemon config, which are used in deployment algorithms to configure
|
||||
ExApp container.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"net": "host",
|
||||
"nextcloud_url": "https://nextcloud.local",
|
||||
"haproxy_password": "some_secure_password",
|
||||
"computeDevice": {
|
||||
"id": "cuda",
|
||||
"name": "CUDA (NVIDIA)",
|
||||
},
|
||||
}
|
||||
|
||||
DeployConfig options
|
||||
********************
|
||||
|
||||
* ``net`` **[required]** - network name to bind docker container to (default: ``host``)
|
||||
* ``nextcloud_url`` **[required]** - Nextcloud URL (e.g. ``https://nextcloud.local``)
|
||||
* ``haproxy_password`` *[optional]* - password for AppAPI Docker Socket Proxy
|
||||
* ``computeDevice`` *[optional]* - Compute device to attach to the daemon (e.g. ``{ "id": "cuda", "label": "CUDA (NVIDIA)" }``)
|
||||
|
||||
Unregister
|
||||
----------
|
||||
|
||||
Unregister Deploy Daemon (DaemonConfig).
|
||||
|
||||
Command: ``app_api:daemon:unregister <daemon-config-name>``
|
||||
|
||||
List registered daemons
|
||||
-----------------------
|
||||
|
||||
List registered Deploy Daemons (DaemonConfigs).
|
||||
|
||||
Command: ``app_api:daemon:list``
|
||||
|
||||
Nextcloud AIO
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
In case of AppAPI installed in AIO, default Deploy Daemon is registered automatically.
|
||||
It is possible to register additional Deploy Daemons with the same ways as described above.
|
||||
|
||||
|
||||
.. _additional_options_list:
|
||||
|
||||
Additional options
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There is a possibility to add additional options to the Deploy Daemon configuration,
|
||||
which are key-value pairs.
|
||||
|
||||
Currently, the following options are available:
|
||||
|
||||
- ``OVERRIDE_APP_HOST`` - can be used to override the host that will be used for ExApp binding (not passed to ExApp container envs)
|
||||
384
admin_manual/exapps_management/DeployConfigurations.rst
Normal file
@@ -0,0 +1,384 @@
|
||||
.. _deploy-configs:
|
||||
|
||||
Deployment configurations
|
||||
=========================
|
||||
|
||||
Currently, only one kind of application deployment is supported:
|
||||
* **Docker Deploy Daemon**
|
||||
|
||||
Docker Deploy Daemon
|
||||
--------------------
|
||||
|
||||
Orchestrates the deployment of applications as Docker containers.
|
||||
|
||||
.. warning::
|
||||
|
||||
The administrator is responsible for the security actions taken to configure the Docker daemon connected to the Nextcloud instance.
|
||||
|
||||
These schemes are only examples of possible configurations.
|
||||
|
||||
We recommend that you use the `AppAPI Docker Socket Proxy <https://github.com/cloud-py-api/docker-socket-proxy>`_ or `AIO Docker Socket Proxy <#nextcloud-in-docker-aio-all-in-one>`_ container.
|
||||
|
||||
There are several Docker Daemon Deploy configurations (example schemes):
|
||||
|
||||
* Nextcloud and Docker on the **same host** (via socket or DockerSocketProxy)
|
||||
* Nextcloud on the host and Docker on a **remote** host (via DockerSocketProxy with HTTPS)
|
||||
* Nextcloud and **ExApps** in the **same Docker** (via DockerSocketProxy)
|
||||
* Nextcloud in AIO Docker and **ExApps** in the **same Docker** (via AIO DockerSocketProxy)
|
||||
|
||||
|
||||
NC & Docker on the Same-Host
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The simplest configuration is when Nextcloud is installed on the host and Docker is on the same host and applications are deployed to it.
|
||||
|
||||
.. mermaid::
|
||||
|
||||
stateDiagram-v2
|
||||
classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain
|
||||
classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain
|
||||
classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px
|
||||
|
||||
Host
|
||||
|
||||
state Host {
|
||||
Nextcloud --> Daemon : /var/run/docker.sock
|
||||
Daemon --> Containers
|
||||
|
||||
state Containers {
|
||||
ExApp1
|
||||
--
|
||||
ExApp2
|
||||
--
|
||||
ExApp3
|
||||
}
|
||||
}
|
||||
|
||||
class Nextcloud nextcloud
|
||||
class Daemon docker
|
||||
class ExApp1 python
|
||||
class ExApp2 python
|
||||
class ExApp3 python
|
||||
|
||||
Suggested config values(template *Custom default*):
|
||||
1. Daemon host: ``/var/run/docker.sock``
|
||||
2. HTTPS checkbox: *not supported using docker socket*
|
||||
3. Network: ``host``
|
||||
4. HaProxy password: **not supported using raw docker socket, should be empty**
|
||||
|
||||
---
|
||||
|
||||
Suggested way to communicate with Docker via `Docker Socket Proxy container <https://github.com/cloud-py-api/docker-socket-proxy>`_.
|
||||
|
||||
.. mermaid::
|
||||
|
||||
stateDiagram-v2
|
||||
classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain
|
||||
classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain
|
||||
classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px
|
||||
|
||||
Host
|
||||
|
||||
state Host {
|
||||
Nextcloud --> DockerSocketProxy: by port
|
||||
Docker --> Containers
|
||||
Docker --> DockerSocketProxy : /var/run/docker.sock
|
||||
|
||||
state Containers {
|
||||
DockerSocketProxy --> ExApp1
|
||||
DockerSocketProxy --> ExApp2
|
||||
DockerSocketProxy --> ExApp3
|
||||
}
|
||||
}
|
||||
|
||||
class Nextcloud nextcloud
|
||||
class Docker docker
|
||||
class ExApp1 python
|
||||
class ExApp2 python
|
||||
class ExApp3 python
|
||||
|
||||
Suggested config values(template *Docker Socket Proxy*):
|
||||
1. Daemon host: ``localhost:2375``
|
||||
Choose **A** or **B** option:
|
||||
A. Docker Socket Proxy should be deployed with ``network=host`` and ``BIND_ADDRESS=127.0.0.1``
|
||||
B. Docker Socket Proxy should be deployed with ``network=bridge`` and it's port should be published to host's 127.0.0.1(e.g. **-p 127.0.0.1:2375:2375**)
|
||||
2. HTTPS checkbox: **disabled**
|
||||
3. Network: ``host``
|
||||
4. HaProxy password: **should not be empty**
|
||||
|
||||
.. warning::
|
||||
|
||||
Be careful with option ``A``, by default **Docker Socket Proxy** binds to ``*`` if ``BIND_ADDRESS`` is not specified during container creation.
|
||||
Check opened ports after finishing configuration.
|
||||
|
||||
|
||||
Docker on a remote host
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Distributed configuration occurs when Nextcloud is installed on one host and Docker is located on a remote host, resulting in the deployment of applications on the remote host.
|
||||
|
||||
Benefit: no performance impact on Nextcloud host.
|
||||
|
||||
In this case, the AppAPI uses a Docker Socket Proxy deployed on remote host to access docker socket and ExApps.
|
||||
|
||||
.. mermaid::
|
||||
|
||||
stateDiagram-v2
|
||||
classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain
|
||||
classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain
|
||||
classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px
|
||||
|
||||
Direction LR
|
||||
|
||||
Host1 --> Host2 : by port
|
||||
|
||||
state Host1 {
|
||||
Nextcloud
|
||||
}
|
||||
|
||||
state Host2 {
|
||||
[*] --> DockerSocketProxy : by port
|
||||
Daemon --> Containers
|
||||
|
||||
state Containers {
|
||||
[*] --> DockerSocketProxy : /var/run/docker.sock
|
||||
DockerSocketProxy --> ExApp1
|
||||
DockerSocketProxy --> ExApp2
|
||||
DockerSocketProxy --> ExApp3
|
||||
}
|
||||
}
|
||||
|
||||
class Nextcloud nextcloud
|
||||
class Daemon docker
|
||||
class ExApp1 python
|
||||
class ExApp2 python
|
||||
class ExApp3 python
|
||||
|
||||
Suggested config values(template *Docker Socket Proxy*):
|
||||
1. Daemon host: ADDRESS_OF_REMOTE_MACHINE (e.g. **server_name.com:2375**)
|
||||
2. HTTPS checkbox: ``enabled``
|
||||
3. Network: ``host``
|
||||
4. HaProxy password: **should not be empty**
|
||||
|
||||
NC & ExApps in the same Docker
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Applications are deployed in the same docker where Nextcloud resides.
|
||||
|
||||
Suggested way to communicate with Docker: via ``docker-socket-proxy``.
|
||||
|
||||
.. mermaid::
|
||||
|
||||
stateDiagram-v2
|
||||
classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain
|
||||
classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain
|
||||
classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px
|
||||
|
||||
Host
|
||||
|
||||
state Host {
|
||||
Daemon --> Containers
|
||||
|
||||
state Containers {
|
||||
[*] --> DockerSocketProxy : /var/run/docker.sock
|
||||
Nextcloud --> DockerSocketProxy: by port
|
||||
--
|
||||
DockerSocketProxy --> ExApp1
|
||||
DockerSocketProxy --> ExApp2
|
||||
}
|
||||
}
|
||||
|
||||
class Nextcloud nextcloud
|
||||
class Daemon docker
|
||||
class ExApp1 python
|
||||
class ExApp2 python
|
||||
class ExApp3 python
|
||||
|
||||
Suggested config values(template *Docker Socket Proxy*):
|
||||
1. Daemon host: nextcloud-appapi-dsp:2375
|
||||
2. HTTPS checkbox: ``disabled``
|
||||
3. Network: `user defined network <https://docs.docker.com/network/#user-defined-networks>`_
|
||||
4. HaProxy password: **should not be empty**
|
||||
|
||||
.. note::
|
||||
Network **should not be the default docker's bridge** as it does not support DNS resolving by container names.
|
||||
|
||||
This means that **Docker Socket Proxy**, **Nextcloud** and **ExApps** containers should all be in the same docker network, different from the default **bridge**.
|
||||
|
||||
|
||||
.. _nextcloud-in-docker-aio-all-in-one:
|
||||
|
||||
Nextcloud in Docker AIO (all-in-one)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In case of AppAPI is in Docker AIO setup (installed in Nextcloud container).
|
||||
|
||||
.. note::
|
||||
|
||||
AIO Docker Socket Proxy container must be enabled.
|
||||
|
||||
.. mermaid::
|
||||
|
||||
stateDiagram-v2
|
||||
classDef docker fill: #1f97ee, color: transparent, font-size: 34px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain
|
||||
classDef docker2 fill: #1f97ee, color: transparent, font-size: 20px, stroke: #364c53, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/docker.png) no-repeat center center / contain
|
||||
classDef nextcloud fill: #006aa3, color: transparent, font-size: 34px, stroke: #045987, stroke-width: 1px, background: url(https://raw.githubusercontent.com/cloud-py-api/app_api/main/docs/img/nextcloud.svg) no-repeat center center / contain
|
||||
classDef python fill: #1e415f, color: white, stroke: #364c53, stroke-width: 1px
|
||||
|
||||
Host
|
||||
|
||||
state Host {
|
||||
Daemon --> Containers
|
||||
|
||||
state Containers {
|
||||
[*] --> NextcloudAIOMasterContainer : /var/run/docker.sock
|
||||
[*] --> DockerSocketProxy : /var/run/docker.sock
|
||||
NextcloudAIOMasterContainer --> Nextcloud
|
||||
AppAPI --> Nextcloud : installed in
|
||||
Nextcloud --> DockerSocketProxy
|
||||
DockerSocketProxy --> ExApp1
|
||||
DockerSocketProxy --> ExApp2
|
||||
DockerSocketProxy --> ExApp3
|
||||
}
|
||||
}
|
||||
|
||||
class Nextcloud nextcloud
|
||||
class Daemon docker
|
||||
class Daemon2 docker2
|
||||
class ExApp1 python
|
||||
class ExApp2 python
|
||||
class ExApp3 python
|
||||
|
||||
AppAPI will automatically create default default DaemonConfig to use AIO Docker Socket Proxy as orchestrator to create ExApp containers.
|
||||
|
||||
.. note::
|
||||
|
||||
Default DaemonConfig will be created only if the default DaemonConfig is not already registered.
|
||||
|
||||
|
||||
Default AIO Deploy Daemon
|
||||
*************************
|
||||
|
||||
Nextcloud AIO has a specifically created Docker Socket Proxy container to be used as the Deploy Daemon in AppAPI.
|
||||
It has `fixed parameters <https://github.com/cloud-py-api/app_api/blob/main/lib/DeployActions/AIODockerActions.php#L52-L74)>`_:
|
||||
|
||||
* Name: ``docker_aio``
|
||||
* Display name: ``AIO Docker Socket Proxy``
|
||||
* Accepts Deploy ID: ``docker-install``
|
||||
* Protocol: ``http``
|
||||
* Host: ``nextcloud-aio-docker-socket-proxy:2375``
|
||||
* Compute device: ``CPU``
|
||||
* Network: ``nextcloud-aio``
|
||||
* Nextcloud URL (passed to ExApps): ``https://$NC_DOMAIN``
|
||||
|
||||
Docker Socket Proxy security
|
||||
****************************
|
||||
|
||||
AIO Docker Socket Proxy has strictly limited access to the Docker APIs described in `HAProxy configuration <https://github.com/nextcloud/all-in-one/blob/main/Containers/docker-socket-proxy/haproxy.cfg>`_.
|
||||
|
||||
|
||||
NC to ExApp Communication
|
||||
-------------------------
|
||||
|
||||
Each type of DeployDaemon necessarily implements the ``resolveExAppUrl`` function.
|
||||
|
||||
It has such prototype:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function resolveExAppUrl(
|
||||
string $appId, string $protocol, string $host, array $deployConfig, int $port, array &$auth
|
||||
) {}
|
||||
|
||||
where:
|
||||
|
||||
* **protocol** is daemon protocol value
|
||||
* **host** is daemon host value, *can be DNS:port or IP:PORT or even path to docker socket*.
|
||||
* **port** is an integer with ExApp port
|
||||
* **deployConfig** can be custom for each Daemon type
|
||||
* **auth** is an optional array, with *Basic Authentication* data if needed to access ExApp
|
||||
|
||||
.. note::
|
||||
|
||||
Starting with AppAPI version ``2.5.0``, the optional additional parameter *OVERRIDE_APP_HOST* can be used to
|
||||
override the host that will be used for ExApp binding.
|
||||
|
||||
It can be ``0.0.0.0`` in some specific configurations, when VPN is used
|
||||
or both Nextcloud instance and ExApps are one the same physical machine but different virtual environments.
|
||||
|
||||
Also you can specify something like ``10.10.2.5`` and in this case ``ExApp`` wil try to bind to that address and
|
||||
AppAPI will try to send request s directly to this address assuming that ExApp itself bound on it.
|
||||
|
||||
The simplest implementation is in **Manual-Install** deploy type:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function resolveExAppUrl(
|
||||
string $appId, string $protocol, string $host, array $deployConfig, int $port, array &$auth
|
||||
): string {
|
||||
$auth = [];
|
||||
if (isset($deployConfig['additional_options']['OVERRIDE_APP_HOST']) &&
|
||||
$deployConfig['additional_options']['OVERRIDE_APP_HOST'] !== ''
|
||||
) {
|
||||
$wideNetworkAddresses = ['0.0.0.0', '127.0.0.1', '::', '::1'];
|
||||
if (!in_array($deployConfig['additional_options']['OVERRIDE_APP_HOST'], $wideNetworkAddresses)) {
|
||||
$host = $deployConfig['additional_options']['OVERRIDE_APP_HOST'];
|
||||
}
|
||||
}
|
||||
return sprintf('%s://%s:%s', $protocol, $host, $port);
|
||||
}
|
||||
|
||||
Here we see that AppAPI send requests to **host**:**port** specified during daemon creation.
|
||||
|
||||
Now let's take a look at the Docker Daemon implementation of ``resolveExAppUrl``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function resolveExAppUrl(
|
||||
string $appId, string $protocol, string $host, array $deployConfig, int $port, array &$auth
|
||||
): string {
|
||||
$auth = [];
|
||||
if (isset($deployConfig['additional_options']['OVERRIDE_APP_HOST']) &&
|
||||
$deployConfig['additional_options']['OVERRIDE_APP_HOST'] !== ''
|
||||
) {
|
||||
$wideNetworkAddresses = ['0.0.0.0', '127.0.0.1', '::', '::1'];
|
||||
if (!in_array($deployConfig['additional_options']['OVERRIDE_APP_HOST'], $wideNetworkAddresses)) {
|
||||
return sprintf(
|
||||
'%s://%s:%s', $protocol, $deployConfig['additional_options']['OVERRIDE_APP_HOST'], $port
|
||||
);
|
||||
}
|
||||
}
|
||||
$host = explode(':', $host)[0];
|
||||
if ($protocol == 'https') {
|
||||
$exAppHost = $host;
|
||||
} elseif (isset($deployConfig['net']) && $deployConfig['net'] === 'host') {
|
||||
$exAppHost = 'localhost';
|
||||
} else {
|
||||
$exAppHost = $appId;
|
||||
}
|
||||
if (isset($deployConfig['haproxy_password']) && $deployConfig['haproxy_password'] !== '') {
|
||||
$auth = [self::APP_API_HAPROXY_USER, $deployConfig['haproxy_password']];
|
||||
}
|
||||
return sprintf('%s://%s:%s', $protocol, $exAppHost, $port);
|
||||
}
|
||||
|
||||
Here we have much more complex algorithm of detecting to where requests should be send.
|
||||
|
||||
First of all if protocol is set to ``https`` AppAPI always send requests to daemon host,
|
||||
and this is in case of ``https`` it is a HaProxy that will forward requests to ExApps that will be listen on ``localhost``
|
||||
|
||||
Briefly it will look like this(*haproxy_host==daemon host value*):
|
||||
|
||||
NC --> *https* --> ``haproxy_host:ex_app_port`` --> *http* --> ``localhost:ex_app_port``
|
||||
|
||||
When protocol is not ``https`` but ``http``, then what will be the endpoint where to send requests is determined by ``$deployConfig['net']`` value.
|
||||
|
||||
If ``net`` is defined and equal to ``host`` then AppAPI assumes that ExApp is installed somewhere in the current host network and will be available on ``localhost`` loop-back adapter.
|
||||
|
||||
NC --> *http* --> ``localhost:ex_app_port``
|
||||
|
||||
In all other cases ExApp should be available by it's name: e.g. when using docker **custom bridge** network all containers available by DNS.
|
||||
|
||||
NC --> *http* --> ``app_container_name:ex_app_port``
|
||||
|
||||
This three different types of communication covers all most popular configurations.
|
||||
85
admin_manual/exapps_management/Installation.rst
Normal file
@@ -0,0 +1,85 @@
|
||||
Installation
|
||||
============
|
||||
|
||||
There are two ways to install the AppAPI: from the `AppStore <https://apps.nextcloud.com/apps/app_api>`_ or from the source code.
|
||||
|
||||
.. note::
|
||||
|
||||
AppAPI 3.0.0 is the last version supported Nextcloud 27.
|
||||
|
||||
|
||||
Installation from the AppStore
|
||||
------------------------------
|
||||
|
||||
Simply navigate to the Apps management page in your Nextcloud and setup the AppAPI from the Tools category.
|
||||
|
||||
Installation from the source code
|
||||
---------------------------------
|
||||
|
||||
To install the AppAPI from the source code, follow these steps:
|
||||
|
||||
1. Clone the AppAPI repository into your apps directory
|
||||
*******************************************************
|
||||
|
||||
Clone the latest main branch:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/cloud-py-api/app_api.git
|
||||
|
||||
or clone a specific version by specifying the version tag:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/cloud-py-api/app_api.git --branch <version-tag>
|
||||
|
||||
where ``<version-tag>`` is the version you want to install.
|
||||
|
||||
|
||||
2. Build frontend assets in production mode
|
||||
********************************************
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
npm ci && npm run build
|
||||
|
||||
3. Enable the AppAPI
|
||||
********************
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./occ app:enable --force app_api
|
||||
|
||||
|
||||
To install it in development mode, follow the instructions on this page: :ref:`dev-setup`.
|
||||
|
||||
4. Setup Deploy daemon
|
||||
**********************
|
||||
|
||||
Upon the successful installation of the AppAPI, a one-time configuration is essential.
|
||||
Details on this configuration can be found in the subsequent section: :ref:`create-deploy-daemon`.
|
||||
|
||||
4.1 Deploy daemon configuration
|
||||
*******************************
|
||||
|
||||
Deploy daemon configuration steps:
|
||||
|
||||
1. Go to the AppAPI admin settings.
|
||||
2. Click on the "Register Daemon" button.
|
||||
3. Fill in the required fields:
|
||||
- ``Name``: unique name of the Deploy daemon
|
||||
- ``Display name``: the name that will be displayed in the UI
|
||||
- ``Deployment method``: by default you will need to choose ``docker_install``, ``manual_install`` is for development or custom use case of manual ExApp installation
|
||||
- ``Daemon Host``: hostname/IP address + port of the Deploy daemon
|
||||
- ``Nextcloud URL``: autofilled with current domain, you might need to change the protocol to http/https depending on your setup
|
||||
- ``Set as default daemon``: check if you want set new Deploy daemon as default
|
||||
- ``Enable https``: check if your Deploy daemon (Docker Socket Proxy) is configured with TLS
|
||||
- Deploy Config:
|
||||
- ``Network``: Docker network name, depends on your networking setup, enforces to "host" if "Enable https" is checked
|
||||
- ``HaProxy password``: password for Docker Socket Proxy, if it is configured with TLS
|
||||
- ``Compute Device``: CPU, CUDA or ROCm, depending on your hardware config on Deploy daemon host machine
|
||||
- ``Add additional option`` (see :ref:`additional_options_list`): setup additional KEY + VALUE deploy config options
|
||||
4. Check connection: to verify configuration is correct
|
||||
5. Register: to save the Deploy daemon configuration
|
||||
|
||||
Deployment configuration examples can be found :ref:`here <deploy-configs>`.
|
||||
117
admin_manual/exapps_management/ManagingExternalApplications.rst
Normal file
@@ -0,0 +1,117 @@
|
||||
Managing External Applications
|
||||
==============================
|
||||
|
||||
There are two ways to manage ExApps:
|
||||
|
||||
1. Using OCC CLI tool
|
||||
2. Using the ExApp Management UI
|
||||
|
||||
|
||||
OCC CLI
|
||||
^^^^^^^
|
||||
|
||||
There are several commands to work with ExApps:
|
||||
|
||||
1. Register
|
||||
2. Unregister
|
||||
3. Update
|
||||
4. Enable
|
||||
5. Disable
|
||||
6. List ExApps
|
||||
7. List ExApp users (removed since AppAPI 3.0.0)
|
||||
8. List ExApp scopes
|
||||
|
||||
Register
|
||||
--------
|
||||
|
||||
Command: ``app_api:app:register [--force-scopes] [--info-xml INFO-XML] [--json-info JSON-INFO] [--] <appid> <daemon-config-name>``
|
||||
|
||||
The register command is the first ExApp installation step.
|
||||
|
||||
Arguments
|
||||
*********
|
||||
|
||||
* ``appid`` - unique name of the ExApp (e.g. ``app_python_skeleton``, must be the same as in deployed container)
|
||||
* ``daemon-config-name`` - unique name of the daemon (e.g. ``docker_local_sock``)
|
||||
|
||||
Options
|
||||
*******
|
||||
|
||||
* ``--force-scopes`` *[optional]* - force scopes approval
|
||||
* ``--json-info JSON-INFO`` **[optional]** - ExApp deploy JSON info (json string)
|
||||
* ``--info-xml INFO-XML`` **[optional]** - path to info.xml file (url or local absolute path)
|
||||
|
||||
|
||||
Unregister
|
||||
----------
|
||||
|
||||
Command: ``app_api:app:unregister [--rm-data] [--force] [--silent] [--] <appid>``
|
||||
|
||||
To remove an ExApp you can use the unregister command.
|
||||
There are additional options to keep the ExApp persistent storage (data volume).
|
||||
|
||||
Arguments
|
||||
*********
|
||||
|
||||
* ``appid`` - unique name of the ExApp (e.g. ``app_python_skeleton``, must be the same as in deployed container)
|
||||
|
||||
Options
|
||||
*******
|
||||
|
||||
* ``--rm-data`` *[optional]* - remove ExApp persistent storage (data volume)
|
||||
* ``--force`` *[optional]* - continue removal even if some error occurs.
|
||||
* ``--silent`` *[optional]* - print a minimum of information, display only some errors, if any.
|
||||
|
||||
Update
|
||||
------
|
||||
|
||||
Command: ``app_api:app:update [--info-xml INFO-XML] [--force-update] [--force-scopes] [-e|--enabled] [--] <appid>``
|
||||
|
||||
ExApp will be updated if there is a new version available.
|
||||
|
||||
Arguments
|
||||
*********
|
||||
|
||||
* ``appid`` - unique name of the ExApp (e.g. ``app_python_skeleton``, must be the same as in deployed container)
|
||||
|
||||
Options
|
||||
*******
|
||||
|
||||
* ``--info-xml INFO-XML`` **[optional]** - path to info.xml file (url or local absolute path)
|
||||
* ``--force-update`` *[optional]* - force ExApp update (do not prompt for confirmation)
|
||||
* ``--force-scopes`` *[optional]* - force scopes approval (accept all scopes)
|
||||
* ``-e|--enabled`` *[optional]* - enable ExApp after update
|
||||
|
||||
Enable
|
||||
------
|
||||
|
||||
Command: ``app_api:app:enable <appid>``
|
||||
|
||||
Disable
|
||||
-------
|
||||
|
||||
Command: ``app_api:app:disable <appid>``
|
||||
|
||||
List ExApps
|
||||
-----------
|
||||
|
||||
Command: ``app_api:app:list``
|
||||
|
||||
ListExApps command will show all ExApps:
|
||||
|
||||
.. code-block::
|
||||
|
||||
ExApps:
|
||||
appid (Display Name): version [enabled/disabled]
|
||||
to_gif_example (To Gif Example): 1.0.0 [enabled]
|
||||
upscaler_example (Upscaler Example): 1.0.0 [enabled]
|
||||
|
||||
Using the ExApp Management UI
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
ExApps management is similar to default Apps management.
|
||||
To access ExApps management navigate using Admin settings dropdown menu or from AppAPI admin settings section.
|
||||
|
||||
.. note::
|
||||
|
||||
ExApps management support only apps from App Store. For manual-install type use CLI ExApps management commands.
|
||||
97
admin_manual/exapps_management/TestDeploy.rst
Normal file
@@ -0,0 +1,97 @@
|
||||
.. _test_deploy:
|
||||
|
||||
Test Deploy Daemon
|
||||
------------------
|
||||
|
||||
You can test each Daemon configuration deployment from the AppAPI Admin settings.
|
||||
|
||||
.. image:: ./img/test_deploy.png
|
||||
|
||||
|
||||
Status Checks
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The Deploy test installs a `test-deploy <https://github.com/cloud-py-api/test-deploy>`_ ExApp
|
||||
to verify each step of the deployment process, including a hardware support check -
|
||||
for each compute device, there is a separate Docker image.
|
||||
|
||||
.. note::
|
||||
The Test Deploy ExApp container is not removed after the test as it's needed for logs and status checks.
|
||||
You can remove it after testing from the External Apps page.
|
||||
The Docker images are also not removed from the Daemon; you can clean up unused images with the ``docker image prune`` command.
|
||||
|
||||
.. image:: ./img/test_deploy_modal_4.png
|
||||
|
||||
|
||||
Register
|
||||
********
|
||||
|
||||
The Register step is the first step; it checks if the ExApp is registered in Nextcloud.
|
||||
|
||||
Image Pull
|
||||
**********
|
||||
|
||||
The Image Pull step downloads the ExApp Docker image.
|
||||
|
||||
Possible errors:
|
||||
|
||||
- Image not found (e.g. not public, no image found for your hardware architecture)
|
||||
- Image pull failed (e.g., due to network issues)
|
||||
- Image pull timeout
|
||||
- Your Docker Socket Proxy is not configured correctly and blocks access to this Docker Engine API
|
||||
|
||||
Container Started
|
||||
*****************
|
||||
|
||||
The Container Started step verifies that the ExApp container is created and started successfully.
|
||||
|
||||
Possible errors:
|
||||
|
||||
- Container failed to start with GPU support (may be missing or misconfigured)
|
||||
- For NVIDIA, refer to the `NVIDIA Docker configuration docs <https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html>`_.
|
||||
- For AMD, refer to the `ROCm Docker configuration docs <https://rocm.docs.amd.com/projects/install-on-linux/en/latest/how-to/docker.html>`_.
|
||||
- The ExApp issue during startup (e.g. not enough memory)
|
||||
|
||||
|
||||
Heartbeat
|
||||
*********
|
||||
|
||||
The Heartbeat step checks if the container's health check is finished and the container is healthy.
|
||||
The ExApp might have additional pre-configuration logic during this step.
|
||||
|
||||
Possible errors:
|
||||
|
||||
- ExApp failed to start a web server, e.g., if the port is already in use (this should be visible in the container logs)
|
||||
- ExApp heartbeat_count keeps increasing, this may indicate that the ExApp couldn't start properly
|
||||
- Nextcloud can not reach the ExApp container, e.g., due to a network issue or a firewall
|
||||
|
||||
Init
|
||||
****
|
||||
|
||||
The Init step checks if the ExApp is initialized and ready to use.
|
||||
During the init step, the ExApp may perform downloads of extra stuff required for it.
|
||||
|
||||
Possible errors:
|
||||
|
||||
- Initialization failed (e.g., due to network issues or timeout)
|
||||
|
||||
|
||||
Enabled
|
||||
*******
|
||||
|
||||
The Enabled step checks if the ExApp is enabled and ready to use.
|
||||
During this step, the ExApp registers all the required and available APIs of the Nextcloud AppFramework.
|
||||
|
||||
Possible errors:
|
||||
|
||||
- ExApp did not respond to the enable request
|
||||
- ExApp failed to enable due to a failure in registering AppAPI Nextcloud AppFramework APIs (this should be visible both in the container logs and in the Nextcloud logs if there are any errors)
|
||||
|
||||
|
||||
Download Logs
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
You can download the logs of the last test deploy attempt container.
|
||||
|
||||
.. note::
|
||||
Downloading Docker container logs is only possible for containers using the json-file or journald logging drivers.
|
||||
BIN
admin_manual/exapps_management/img/app_api_1.png
Executable file
|
After Width: | Height: | Size: 673 KiB |
BIN
admin_manual/exapps_management/img/app_api_2.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
BIN
admin_manual/exapps_management/img/app_api_3.png
Normal file
|
After Width: | Height: | Size: 314 KiB |
BIN
admin_manual/exapps_management/img/app_api_4.png
Normal file
|
After Width: | Height: | Size: 221 KiB |
BIN
admin_manual/exapps_management/img/docker.png
Executable file
|
After Width: | Height: | Size: 6.3 KiB |
11
admin_manual/exapps_management/img/nextcloud.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 127 87.2" style="enable-background:new 0 0 127 87.2;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<path id="path1052" class="st0" d="M63.6,3.8C51,3.8,40.3,12.3,37,23.9c-2.9-6.1-9.1-10.4-16.3-10.4c-9.9,0-18,8.1-18,18 c0,9.9,8.1,18,18,18c7.2,0,13.4-4.3,16.3-10.4c3.3,11.6,14,20.1,26.6,20.1c12.5,0,23.1-8.4,26.5-19.8c2.9,6,9.1,10.2,16.2,10.2 c9.9,0,18-8.1,18-18c0-9.9-8.1-18-18-18c-7.1,0-13.2,4.2-16.2,10.2C86.7,12.2,76.1,3.8,63.6,3.8z M63.6,14.3 c9.5,0,17.1,7.6,17.1,17.1c0,9.5-7.6,17.1-17.1,17.1c-9.5,0-17.1-7.6-17.1-17.1C46.5,21.9,54.1,14.3,63.6,14.3z M20.7,24 c4.2,0,7.4,3.3,7.4,7.4c0,4.2-3.3,7.4-7.4,7.4c-4.2,0-7.4-3.3-7.4-7.4C13.3,27.3,16.6,24,20.7,24z M106.3,24c4.2,0,7.4,3.3,7.4,7.4 c0,4.2-3.3,7.4-7.4,7.4c-4.2,0-7.4-3.3-7.4-7.4C98.8,27.3,102.1,24,106.3,24z"></path>
|
||||
<path id="path1174" class="st0" d="M15.4,67.4c-0.4,0-0.5,0.2-0.5,0.6v14.6c0,0.4,0.2,0.5,0.5,0.5h0.4c0.4,0,0.5-0.2,0.5-0.5V70.4 l7.9,12.3c0,0.1,0.1,0.1,0.1,0.1c0,0,0,0,0,0c0,0,0.1,0,0.1,0.1c0,0,0,0,0.1,0c0,0,0,0,0,0c0.1,0,0.1,0,0.2,0h0.4 c0.4,0,0.5-0.2,0.5-0.5V68c0-0.4-0.2-0.6-0.5-0.6h-0.4c-0.4,0-0.6,0.2-0.6,0.6v12.1l-7.9-12.3c0,0-0.1-0.1-0.1-0.1 c-0.1-0.1-0.2-0.2-0.4-0.2L15.4,67.4z M110.8,67.6c-0.4,0-0.2,0.2-0.2,0.6v5c0,0.5,0,0.9,0,0.9h0c0,0-1-2.2-3.6-2.2 c-2.9,0-5,2.3-4.9,5.7c0,3.4,1.9,5.8,4.8,5.8c2.9,0,3.8-2.3,3.8-2.3h0.1c0,0-0.1,0.3-0.1,0.7v0.9c0,0.4,0.2,0.5,0.6,0.5h0.4 c0.4,0,0.5-0.2,0.5-0.6V68.2c0-0.4-0.6-0.6-0.9-0.6H110.8z M71.8,67.7c-0.4,0-0.1,0.2-0.1,0.6v12.3c0,2.4,1.6,2.7,2.5,2.7 c0.4,0,0.6-0.2,0.6-0.6v-0.4c0-0.4-0.2-0.5-0.5-0.5c-0.5-0.1-1.2-0.2-1.2-1.6v-12c0-0.4-0.6-0.6-0.9-0.6L71.8,67.7z M53.8,69 c-0.4,0-0.6,0.2-0.6,0.6v2.6v1.3v5.7c0,2.6,1.5,4.1,3.9,4.1c0.5,0,0.6-0.1,0.6-0.5v-0.3c0-0.4-0.1-0.5-0.6-0.6 c-0.9-0.1-2.4-0.4-2.4-2.9v-5.5h2.3c0.4,0,0.6-0.1,0.6-0.5v-0.2c0-0.4-0.2-0.6-0.6-0.6h-2.3v-2.6c0-0.4-0.1-0.6-0.5-0.6L53.8,69z M33.8,71.8c-3,0-5.4,2.2-5.5,5.8c0,3.4,2.5,5.8,5.8,5.8c1.8,0,3.1-0.8,3.7-1.2c0.3-0.2,0.3-0.5,0.2-0.7l-0.2-0.2 c-0.2-0.3-0.4-0.4-0.7-0.2c-0.5,0.4-1.5,1-2.9,1c-2.3,0-4.2-1.6-4.3-4.4h8c0.3,0,0.6-0.3,0.6-0.6C38.4,73.9,36.8,71.8,33.8,71.8z M65,71.8c-3.3,0-5.8,2.4-5.8,5.8c0,3.4,2.5,5.8,5.8,5.8c2,0,3.4-1,3.9-1.4c0.3-0.3,0.3-0.5,0.1-0.8L68.8,81 c-0.2-0.3-0.4-0.4-0.7-0.2C67.6,81.3,66.6,82,65,82c-2.4,0-4.3-1.8-4.3-4.4c0-2.7,1.9-4.5,4.3-4.5c1.3,0,2.3,0.7,2.8,1 c0.3,0.2,0.6,0.2,0.8-0.1l0.2-0.3c0.3-0.3,0.2-0.6-0.1-0.8C68.1,72.6,66.9,71.8,65,71.8L65,71.8z M81.9,71.8 c-3.2,0-5.8,2.5-5.8,5.7c0,3.3,2.6,5.8,5.8,5.8c3.2,0,5.8-2.5,5.8-5.8C87.8,74.3,85.1,71.8,81.9,71.8z M49.5,72 c-0.1,0-0.2,0.1-0.4,0.2l-2,2.4l-1.5,1.8l-2.3-2.7L42,72.2c-0.1-0.1-0.2-0.2-0.4-0.2c-0.1,0-0.3,0-0.4,0.2l-0.3,0.3 c-0.3,0.2-0.3,0.5,0,0.7l2,2.4l1.7,2l-2.5,2.9c0,0,0,0,0,0L40.9,82c-0.2,0.3-0.2,0.6,0.1,0.8l0.3,0.3c0.3,0.2,0.5,0.2,0.7-0.1 l2-2.4l1.5-1.8l2.3,2.7c0,0,0,0,0,0l1.2,1.5c0.2,0.3,0.5,0.3,0.8,0.1l0.3-0.3c0.3-0.2,0.3-0.5,0-0.7l-2-2.4l-1.7-2l2.5-2.9 c0,0,0,0,0,0l1.2-1.5c0.2-0.3,0.2-0.6-0.1-0.8l-0.3-0.3C49.7,72,49.6,71.9,49.5,72L49.5,72z M90.7,72c-0.4,0-0.5,0.2-0.5,0.6v6.5 c0,2.9,2.1,4.3,4.7,4.3c2.6,0,4.7-1.4,4.7-4.3v-6.5c0.1-0.4-0.1-0.6-0.5-0.6h-0.4c-0.4,0-0.6,0.2-0.6,0.6v6.1 c0,1.7-1.1,3.3-3.3,3.3c-2.1,0-3.3-1.6-3.3-3.3v-6.1c0-0.4-0.2-0.6-0.6-0.6L90.7,72z M33.8,73c1.6,0,3,1.2,3.1,3.5h-6.9 C30.3,74.3,31.9,73,33.8,73z M81.9,73.1c2.4,0,4.3,1.9,4.3,4.4c0,2.6-1.9,4.5-4.3,4.5c-2.4,0-4.3-2-4.3-4.5 C77.6,75.1,79.6,73.1,81.9,73.1z M107.1,73.1c2.4,0,3.5,2.2,3.5,4.4c0,3.2-1.7,4.5-3.6,4.5c-2.1,0-3.5-1.8-3.5-4.5 C103.5,74.8,105.1,73.1,107.1,73.1z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
BIN
admin_manual/exapps_management/img/test_deploy.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
admin_manual/exapps_management/img/test_deploy_modal_2.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
admin_manual/exapps_management/img/test_deploy_modal_4.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
13
admin_manual/exapps_management/index.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
=================
|
||||
ExApps management
|
||||
=================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Installation
|
||||
DeployConfigurations
|
||||
CreationOfDeployDaemon
|
||||
TestDeploy
|
||||
ManagingExternalApplications
|
||||
Concepts
|
||||