diff --git a/.gitignore b/.gitignore index d11f60d3..bf009e5c 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ node_modules .venv vendor +_build diff --git a/README.md b/README.md index 1fb42081..8f788908 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Nextcloud App Ecosystem V2 provides a new API for external apps on different pro | Currently in a prototyping stage +Docs can be found [here](https://cloud-py-api.github.io/app_ecosystem_v2/). + ## Dev changes to Nextcloud `base.php` adjustment for authentication of Ex apps ([patch](./base_php.patch)). diff --git a/docs/definitions.rst b/docs/definitions.rst new file mode 100644 index 00000000..88aabf56 --- /dev/null +++ b/docs/definitions.rst @@ -0,0 +1,9 @@ +=========== +Definitions +=========== + +AppEcosystemV2 brings out the following terms: + +* ExApp (External App) - the app on another (from PHP) programming language, which can be hosted separately or inside container +* DaemonConfig - configuration of orchestration daemon (e.g. Docker) where ExApps are deployed +* ExAppConfig - similar to Nextcloud `app_config`, but for ExApps configuration diff --git a/docs/deploy/index.rst b/docs/deploy/index.rst new file mode 100644 index 00000000..47083d85 --- /dev/null +++ b/docs/deploy/index.rst @@ -0,0 +1,212 @@ +========== +Deployment +========== + +Overview +-------- + +AppEcosystemV2 ExApps deployment process in short consists of 3 steps: + +1. `Daemon config registration`_ +2. `ExApp deployment`_ +3. `ExApp registration`_ + + +Daemon config registration +-------------------------- + +The first step is to register Daemon config, where your ExApps will be deployed. + +.. note:: + For now only Docker daemon (`accepts-deploy-id: docker-install`) is supported. + +This can be done by `occ` CLI command **app_ecosystem_v2:daemon:register**: + +.. code-block:: bash + + app_ecosystem_v2:daemon:register [--net NET] [--host HOST] [--] + +Arguments +********* + + * `name` - `[required]` unique name of the daemon (e.g. `docker_local_sock`) + * `display-name` - `[required]` name of the daemon (e.g. `My Local Docker`, will be displayed in the UI) + * `accepts-deploy-id` - `[required]` type of deployment (for now only `docker-install` is supported) + * `protocol` - `[required]` protocol used to connect to the daemon (`unix-socket`, `network`) + * `host` - `[required]` host of the daemon (e.g. `/var/run/docker.sock` for `unix-socket` protocol or `host:port` for `http(s)` protocol) + * `nextcloud_url` - `[required]` 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`) + * `--host HOST` - `[required]` host to expose daemon to (defaults to ExApp appid) + +Deploy config +************* + +Deploy config is a set of additional options in Daemon config, which are used in deployment algorithms to configure +ExApp container. + +.. code-block:: json + + { + "net": "nextcloud", + "host": null, + "nextcloud_url": "https://nextcloud.local" + } + + +Deploy config options +""""""""""""""""""""" + + * `net` - `[required]` network name to bind docker container to (default: `host`) + * `host` - `[optional]` in case Docker is on remote host, this should be a hostname of remote machine + * `nextcloud_url` - `[required]` Nextcloud URL (e.g. `https://nextcloud.local`) + + +.. note:: + Common configurations are tested by CI in our repository, see `workflow on github `_ + +Example +******* + +Example of `occ` **app_ecosystem_v2:daemon:register** command: + +.. code-block:: bash + + sudo -u www-data php occ app_ecosystem_v2:daemon:register docker_local_sock "My Local Docker" docker-install unix-socket /var/run/docker.sock "https://nextcloud.local" --net nextcloud + + +ExApp deployment +---------------- + +Second step is to deploy ExApp on registered daemon. +This can be done by `occ` CLI command **app_ecosystem_v2:app:deploy**: + +.. code-block:: bash + + app_ecosystem_v2:app:deploy [--info-xml INFO-XML] [--ssl_key SSL_KEY] [--ssl_password SSL_PASSWORD] [--ssl_cert SSL_CERT] [--ssl_cert_password SSL_CERT_PASSWORD] [-e|--env ENV] [--] + +.. warning:: + After successful deployment (pull, create and start container), there is a heartbeat check with 1 hour timeout (will be configurable). + If command seems to be stuck, check if ExApp is running and accessible by Nextcloud instance. + +.. note:: + For development this step is skipped, as ExApp is deployed and started manually by developer. + +Arguments +********* + + * `appid` - `[required]` unique name of the ExApp (e.g. `app_python_skeleton`, must be the same as in `info.xml`) + * `daemon-config-name` - `[required]` unique name of the daemon (e.g. `docker_local_sock`) + +Options +******* + + * `--info-xml INFO-XML` - `[required]` path to info.xml file (url or local absolute path) + * `--ssl_key SSL_KEY` - `[optional]` path to SSL key file (local absolute path) + * `--ssl_password SSL_PASSWORD` - `[optional]` SSL key password + * `--ssl_cert SSL_CERT` - `[optional]` path to SSL cert file (local absolute path) + * `--ssl_cert_password SSL_CERT_PASSWORD` - `[optional]` SSL cert password + * `-e|--env ENV` - `[optional]` additional environment variables (e.g. `-e "MY_VAR=123" -e "MY_VAR2=456"`) + +Deploy result JSON output +************************* + +Example of deploy result JSON output: + +.. code-block:: + + { + "appid": "app_python_skeleton", + "name":"App Python Skeleton", + "daemon_config_name": "local_docker_sock", + "version":"1.0.0", + "secret":"***generated-secret***", + "host":"app_python_skeleton", + "port":"9001", + "system_app": true + } + +This JSON output is used in ExApp registration step. + +Deploy env variables +******************** + +Deploy env variables are used to configure ExApp container. +The following env variables are required and built automatically: + + * `AE_VERSION` - AppEcosystemV2 version + * `APP_SECRET` - generated shared secret used for AppEcosystemV2 authentication + * `APP_ID` - ExApp appid + * `APP_VERSION` - ExApp version + * `APP_HOST` - host ExApp is listening on + * `APP_PORT` - port ExApp is listening on (randomly selected by AppEcosystemV2) + * `NEXTCLOUD_URL` - Nextcloud URL to connect to + +.. note:: + additional envs can be passed using multiple `--env ENV_NAME=ENV_VAL` options) + +Docker daemon remote +******************** + +If you want to connect to remote docker daemon with TLS enabled, you need to provide SSL key and cert by provided options. +Important: before deploy you need to import ca.pem file using occ command: + +``` +php occ security:certificates:import /path/to/ca.pem +``` + +The daemon must be configured with `protocol=http|https`, `host=https://dockerapihost`, `port=8443`. +More info about how to configure daemon will be added soon. + +ExApp registration +------------------ + +Final step is to register ExApp in Nextcloud. +This can be done by `occ` CLI command **app_ecosystem_v2:app:register**: + +.. code-block:: bash + + app_ecosystem_v2:app:register [-e|--enabled] [--force-scopes] [--] + +Arguments +********* + + * `deploy-json-output` - `[required]` JSON output from deploy step + +Options +******* + + * `-e|--enabled` - `[optional]` enable ExApp after registration + * `--force-scopes` - `[optional]` force scopes approval + + +This step can be combined with deployment step into one command: + +.. code-block:: bash + + sudo -u www-data php occ app_ecosystem_v2:app:register "$(sudo -u www-data php occ app_ecosystem_v2:app:deploy app_python_skeleton docker_local_sock --info-xml https://raw.githubusercontent.com/cloud-py-api/py_app_v2-skeleton/main/appinfo/info.xml)" --enabled --force-scopes + + +ExApp info.xml schema +--------------------- + +ExApp info.xml (`example repo `_) file is used to describe ExApp params. +It is used to generate ExApp docker container and to register ExApp in Nextcloud. +It has the same structure as Nextcloud appinfo/info.xml file, but with some additional fields: + +.. code-block:: xml + + ... + + + ghcr.io + cloud-py-api/py_app_v2-skeleton + latest + + http + 0 + + ... diff --git a/docs/development/index.rst b/docs/development/index.rst new file mode 100644 index 00000000..59afe343 --- /dev/null +++ b/docs/development/index.rst @@ -0,0 +1,10 @@ +=========== +Development +=========== + +This section will contain all the information required to develop the project. + + +Requirements +------------ + diff --git a/docs/index.rst b/docs/index.rst index 82b36574..ca128bc2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,13 @@ -=========================== -Docs for the AppEcosystemV2 -=========================== +============================ +AppEcosystemV2 documentation +============================ Welcome to the amazing docs that we will write for AppEcosystemV2! + + +.. toctree:: + :maxdepth: 2 + + definitions.rst + development/index.rst + deploy/index.rst diff --git a/lib/Command/Daemon/RegisterDaemon.php b/lib/Command/Daemon/RegisterDaemon.php index 18d268b7..113f718b 100644 --- a/lib/Command/Daemon/RegisterDaemon.php +++ b/lib/Command/Daemon/RegisterDaemon.php @@ -78,6 +78,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'net' => $input->getOption('net') ?? 'host', 'host' => $input->getOption('host'), 'nextcloud_url' => $nextcloudUrl, + // TODO: Add SSL cert config here ]; $daemonConfig = $this->daemonConfigService->registerDaemonConfig([ diff --git a/lib/Command/ExApp/Deploy.php b/lib/Command/ExApp/Deploy.php index 6014da51..e8313da9 100644 --- a/lib/Command/ExApp/Deploy.php +++ b/lib/Command/ExApp/Deploy.php @@ -140,6 +140,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int ], $envParams, $deployConfig); $containerParams['env'] = $envs; + // TODO: Move SSL part to DaemonConfig->deployConfig $sslParams = [ 'ssl_key' => $input->getOption('ssl_key'), 'ssl_key_password' => $input->getOption('ssl_key_password'), diff --git a/lib/Service/DaemonConfigService.php b/lib/Service/DaemonConfigService.php index 267feff4..2d65fd83 100644 --- a/lib/Service/DaemonConfigService.php +++ b/lib/Service/DaemonConfigService.php @@ -137,7 +137,7 @@ public function getDaemonConfigByName(string $name): ?DaemonConfig { $daemonConfig = $this->mapper->findByName($name); $this->cache->set($cacheKey, $daemonConfig, Application::CACHE_TTL); return $daemonConfig; - } catch (Exception $e) { + } catch (DoesNotExistException|MultipleObjectsReturnedException|Exception $e) { $this->logger->error('Failed to get daemon config by name. Error: ' . $e->getMessage()); return null; }