Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

occ app_api:app:unregister rework #127

Merged
merged 9 commits into from
Nov 26, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 31 additions & 18 deletions .github/workflows/tests-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,6 @@ jobs:
repository: nextcloud/server
ref: ${{ matrix.server-version }}

- name: Checkout Notifications
uses: actions/checkout@v3
with:
repository: nextcloud/notifications
ref: ${{ matrix.server-version }}
path: apps/notifications

- name: Checkout AppAPI
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
with:
Expand Down Expand Up @@ -93,7 +86,6 @@ jobs:
--admin-user admin --admin-pass admin
./occ config:system:set loglevel --value=0 --type=integer
./occ config:system:set debug --value=true --type=boolean
./occ app:enable notifications
./occ app:enable --force ${{ env.APP_NAME }}

- name: Test deploy
Expand All @@ -106,8 +98,6 @@ jobs:
--info-xml https://raw.githubusercontent.com/cloud-py-api/nc_py_api/main/examples/as_app/skeleton/appinfo/info.xml
./occ app_api:app:enable skeleton
./occ app_api:app:disable skeleton
./occ app_api:app:unregister skeleton --silent
./occ app_api:daemon:unregister docker_local_sock

- name: Check logs
run: |
Expand All @@ -120,6 +110,14 @@ jobs:
docker inspect nc_app_skeleton | json_pp > container.json
docker logs nc_app_skeleton > container.log 2>&1

- name: Unregister Skeleton & Daemon
run: |
./occ app_api:app:unregister skeleton
./occ app_api:daemon:unregister docker_local_sock

- name: Test OCC commands(docker)
run: python3 apps/${{ env.APP_NAME }}/tests/test_occ_commands_docker.py

- name: Upload Container info
if: always()
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -176,8 +174,6 @@ jobs:
--info-xml https://raw.githubusercontent.com/cloud-py-api/nc_py_api/main/examples/as_app/skeleton/appinfo/info.xml
docker exec nextcloud sudo -u www-data php occ app_api:app:enable skeleton
docker exec nextcloud sudo -u www-data php occ app_api:app:disable skeleton
docker exec nextcloud sudo -u www-data php occ app_api:app:unregister skeleton --silent
docker exec nextcloud sudo -u www-data php occ app_api:daemon:unregister docker_local_sock

- name: Copy NC log to host
run: docker cp nextcloud:/var/www/html/data/nextcloud.log nextcloud.log
Expand All @@ -193,6 +189,11 @@ jobs:
docker inspect nc_app_skeleton | json_pp > container.json
docker logs nc_app_skeleton > container.log 2>&1

- name: Unregister Skeleton & Daemon
run: |
docker exec nextcloud sudo -u www-data php occ app_api:app:unregister skeleton
docker exec nextcloud sudo -u www-data php occ app_api:daemon:unregister docker_local_sock

- name: Upload Container info
if: always()
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -254,8 +255,6 @@ jobs:
--info-xml https://raw.githubusercontent.com/cloud-py-api/nc_py_api/main/examples/as_app/skeleton/appinfo/info.xml
docker exec nextcloud sudo -u www-data php occ app_api:app:enable skeleton
docker exec nextcloud sudo -u www-data php occ app_api:app:disable skeleton
docker exec nextcloud sudo -u www-data php occ app_api:app:unregister skeleton --silent
docker exec nextcloud sudo -u www-data php occ app_api:daemon:unregister docker_by_port

- name: Copy NC log to host
run: docker cp nextcloud:/var/www/html/data/nextcloud.log nextcloud.log
Expand All @@ -271,6 +270,11 @@ jobs:
docker inspect nc_app_skeleton | json_pp > container.json
docker logs nc_app_skeleton > container.log 2>&1

- name: Unregister Skeleton & Daemon
run: |
docker exec nextcloud sudo -u www-data php occ app_api:app:unregister skeleton
docker exec nextcloud sudo -u www-data php occ app_api:daemon:unregister docker_by_port

- name: Upload Container info
if: always()
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -331,8 +335,6 @@ jobs:
--info-xml https://raw.githubusercontent.com/cloud-py-api/nc_py_api/main/examples/as_app/skeleton/appinfo/info.xml
docker exec nextcloud sudo -u www-data php occ app_api:app:enable skeleton
docker exec nextcloud sudo -u www-data php occ app_api:app:disable skeleton
docker exec nextcloud sudo -u www-data php occ app_api:app:unregister skeleton --silent
docker exec nextcloud sudo -u www-data php occ app_api:daemon:unregister docker_by_port

- name: Copy NC log to host
run: docker cp nextcloud:/var/www/html/data/nextcloud.log nextcloud.log
Expand All @@ -348,6 +350,11 @@ jobs:
docker inspect nc_app_skeleton | json_pp > container.json
docker logs nc_app_skeleton > container.log 2>&1

- name: Unregister Skeleton & Daemon
run: |
docker exec nextcloud sudo -u www-data php occ app_api:app:unregister skeleton
docker exec nextcloud sudo -u www-data php occ app_api:daemon:unregister docker_by_port

- name: Upload Container info
if: always()
uses: actions/upload-artifact@v3
Expand Down Expand Up @@ -473,8 +480,6 @@ jobs:
--info-xml https://raw.githubusercontent.com/cloud-py-api/nc_py_api/main/examples/as_app/skeleton/appinfo/info.xml
./occ app_api:app:enable skeleton
./occ app_api:app:disable skeleton
./occ app_api:app:unregister skeleton --silent
./occ app_api:daemon:unregister docker_local_sock

- name: Check logs
run: |
Expand All @@ -487,6 +492,14 @@ jobs:
docker inspect nc_app_skeleton | json_pp > container.json
docker logs nc_app_skeleton > container.log 2>&1

- name: Unregister Skeleton & Daemon
run: |
./occ app_api:app:unregister skeleton
./occ app_api:daemon:unregister docker_local_sock

- name: Test OCC commands(docker)
run: python3 apps/${{ env.APP_NAME }}/tests/test_occ_commands_docker.py

- name: Check redis keys
run: |
docker exec redis redis-cli keys '*app_api*' || error
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/tests-special.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ concurrency:
group: tests-special-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

env:
NEXTCLOUD_URL: "http://localhost:8080/"
APP_ID: "nc_py_api"
APP_PORT: 9009
APP_VERSION: "1.0.0"
APP_SECRET: "tC6vkwPhcppjMykD1r0n9NlI95uJMBYjs5blpIcA1PAdoPDmc5qoAjaBAkyocZ6E"

jobs:
app-version-higher:
runs-on: ubuntu-22.04
name: ExApp version higher
env:
NEXTCLOUD_URL: "http://localhost:8080/"
APP_ID: "nc_py_api"
APP_PORT: 9009
APP_VERSION: "1.0.0"
APP_SECRET: "tC6vkwPhcppjMykD1r0n9NlI95uJMBYjs5blpIcA1PAdoPDmc5qoAjaBAkyocZ6E"

services:
postgres:
Expand Down
23 changes: 8 additions & 15 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ concurrency:
group: tests-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

env:
NEXTCLOUD_URL: "http://localhost:8080/"
APP_ID: "nc_py_api"
APP_PORT: 9009
APP_VERSION: "1.0.0"
APP_SECRET: "tC6vkwPhcppjMykD1r0n9NlI95uJMBYjs5blpIcA1PAdoPDmc5qoAjaBAkyocZ6E"
SKIP_NC_CLIENT_TESTS: 1

jobs:
nc-py-api-pgsql:
runs-on: ubuntu-22.04
Expand All @@ -27,13 +35,6 @@ jobs:
php-version: "8.2"
- server-version: "master"
php-version: "8.3"
env:
NEXTCLOUD_URL: "http://localhost:8080/"
APP_ID: "nc_py_api"
APP_PORT: 9009
APP_VERSION: "1.0.0"
APP_SECRET: "tC6vkwPhcppjMykD1r0n9NlI95uJMBYjs5blpIcA1PAdoPDmc5qoAjaBAkyocZ6E"
SKIP_NC_CLIENT_TESTS: 1

services:
postgres:
Expand Down Expand Up @@ -145,14 +146,6 @@ jobs:
runs-on: ubuntu-22.04
name: NC_Py_API • stable27 • 8.1 • MySQL

env:
NEXTCLOUD_URL: "http://localhost:8080/"
APP_ID: "nc_py_api"
APP_PORT: 9009
APP_VERSION: "1.0.0"
APP_SECRET: "tC6vkwPhcppjMykD1r0n9NlI95uJMBYjs5blpIcA1PAdoPDmc5qoAjaBAkyocZ6E"
SKIP_NC_CLIENT_TESTS: 1

services:
mysql:
image: ghcr.io/nextcloud/continuous-integration-mysql-8.1:latest
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

## [1.3.0 - 2023-12-0x]

### Changed

- Reworked: `app_api:app:unregister` occ cli command, make it much robust. #127

## [1.2.2 - 2023-11-13]

### Fixed
Expand Down
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,8 @@
"psr-4": {
"OCP\\": "vendor/nextcloud/ocp/OCP"
}
}
},
"require": {
"ext-simplexml": "*"
}
}
10 changes: 5 additions & 5 deletions docs/ManagingExternalApplications.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ Options
Unregister
----------

Command: ``app_api:app:unregister [--silent] [--rm-container] [--rm-data] [--] <appid>``
Command: ``app_api:app:unregister [--keep-data] [--force] [--silent] [--] <appid>``

To remove an ExApp you can use the unregister command.
There are additional options to remove the ExApp container and persistent storage (data volume).
There are additional options to keep the ExApp persistent storage (data volume).

Arguments
*********
Expand All @@ -78,9 +78,9 @@ Arguments
Options
*******

* ``--silent`` *[optional]* - do not disable ExApp before unregister
* ``--rm-container`` *[optional]* - remove ExApp container
* ``--rm-data`` *[optional]* - remove ExApp persistent storage (data volume)
* ``--keep-data`` *[optional]* - keep 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
------
Expand Down
107 changes: 72 additions & 35 deletions lib/Command/ExApp/Unregister.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,67 +30,104 @@ protected function configure(): void {

$this->addArgument('appid', InputArgument::REQUIRED);

$this->addOption('silent', null, InputOption::VALUE_NONE, 'Unregister only from Nextcloud. Do not send request to external app.');
$this->addOption('rm-container', null, InputOption::VALUE_NONE, 'Remove ExApp container');
$this->addOption('rm-data', null, InputOption::VALUE_NONE, 'Remove ExApp data (volume)');
$this->addOption(
'silent',
null,
InputOption::VALUE_NONE,
'Print only minimum and only errors.');
$this->addOption(
'force',
null,
InputOption::VALUE_NONE,
'Continue removal even if errors.');
$this->addOption('keep-data', null, InputOption::VALUE_NONE, 'Keep ExApp data (volume)');

$this->addUsage('test_app');
$this->addUsage('test_app --silent');
$this->addUsage('test_app --rm');
$this->addUsage('test_app --keep-data');
$this->addUsage('test_app --silent --force --keep-data');
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$appId = $input->getArgument('appid');
$silent = $input->getOption('silent');
$force = $input->getOption('force');
$keep_data = $input->getOption('keep-data');

$exApp = $this->service->getExApp($appId);
if ($exApp === null) {
if ($silent) {
return 0;
}
$output->writeln(sprintf('ExApp %s not found. Failed to unregister.', $appId));
return 1;
}

$silent = $input->getOption('silent');

if (!$silent) {
if ($this->service->disableExApp($exApp)) {
if ($exApp->getEnabled()) {
if (!$this->service->disableExApp($exApp)) {
if (!$silent) {
$output->writeln(sprintf('Error during disabling %s ExApp.', $appId));
}
if (!$force) {
return 1;
}
} elseif (!$silent) {
$output->writeln(sprintf('ExApp %s successfully disabled.', $appId));
} else {
$output->writeln(sprintf('ExApp %s not disabled. Failed to disable.', $appId));
return 1;
}
}

$exApp = $this->service->unregisterExApp($appId);
if ($exApp === null) {
$output->writeln(sprintf('Failed to unregister ExApp %s.', $appId));
return 1;
}

$rmContainer = $input->getOption('rm-container');
if ($rmContainer) {
$daemonConfig = $this->daemonConfigService->getDaemonConfigByName($exApp->getDaemonConfigName());
if ($daemonConfig === null) {
$output->writeln(sprintf('Failed to get ExApp %s DaemonConfig by name %s', $appId, $exApp->getDaemonConfigName()));
$daemonConfig = $this->daemonConfigService->getDaemonConfigByName($exApp->getDaemonConfigName());
if ($daemonConfig === null) {
if (!$silent) {
$output->writeln(
sprintf('Failed to get ExApp %s DaemonConfig by name %s', $appId, $exApp->getDaemonConfigName())
);
}
if (!$force) {
return 1;
}
if ($daemonConfig->getAcceptsDeployId() === $this->dockerActions->getAcceptsDeployId()) {
$this->dockerActions->initGuzzleClient($daemonConfig);
[$stopResult, $removeResult] = $this->dockerActions->removePrevExAppContainer($this->dockerActions->buildDockerUrl($daemonConfig), $this->dockerActions->buildExAppContainerName($appId));
if (isset($stopResult['error']) || isset($removeResult['error'])) {
}
if ($daemonConfig->getAcceptsDeployId() === $this->dockerActions->getAcceptsDeployId()) {
$this->dockerActions->initGuzzleClient($daemonConfig);
[$stopResult, $removeResult] = $this->dockerActions->removePrevExAppContainer(
$this->dockerActions->buildDockerUrl($daemonConfig), $this->dockerActions->buildExAppContainerName($appId)
);
if (isset($stopResult['error']) || isset($removeResult['error'])) {
if (!$silent) {
$output->writeln(sprintf('Failed to remove ExApp %s container', $appId));
} else {
$rmData = $input->getOption('rm-data');
if ($rmData) {
$removeVolumeResult = $this->dockerActions->removeVolume($this->dockerActions->buildDockerUrl($daemonConfig), $this->dockerActions->buildExAppVolumeName($appId));
if (isset($removeVolumeResult['error'])) {
$output->writeln(sprintf('Failed to remove ExApp %s volume %s', $appId, $appId . '_data'));
}
}
if (!$force) {
return 1;
}
} elseif (!$silent) {
$output->writeln(sprintf('ExApp %s container successfully removed', $appId));
}
if (!$keep_data) {
$volumeName = $this->dockerActions->buildExAppVolumeName($appId);
$removeVolumeResult = $this->dockerActions->removeVolume(
$this->dockerActions->buildDockerUrl($daemonConfig), $volumeName
);
if (!$silent) {
if (isset($removeVolumeResult['error'])) {
$output->writeln(sprintf('Failed to remove ExApp %s volume: %s', $appId, $volumeName));
} else {
$output->writeln(sprintf('ExApp %s data volume successfully removed', $appId));
}
$output->writeln(sprintf('ExApp %s container successfully removed', $appId));
}
}
}

$output->writeln(sprintf('ExApp %s successfully unregistered.', $appId));
if ($this->service->unregisterExApp($appId) === null) {
if (!$silent) {
$output->writeln(sprintf('Failed to unregister ExApp %s.', $appId));
}
if (!$force) {
return 1;
}
}
if (!$silent) {
$output->writeln(sprintf('ExApp %s successfully unregistered.', $appId));
}
return 0;
}
}
Loading
Loading