Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,25 @@ You can use it to set all projects of an organization to use a storage backend.
php ./cli.php manage:set-organization-storage-backend [--force/-f] <manage-token> <organization-id> <storage-backend-id> <hostname-suffix>
```

## Delete Storage Backend
Delete one or more storage backends from a stack by their IDs. Dry-run by default.

- Run the command
```
php ./cli.php manage:delete-backend [--force/-f] <manage-token> <backend-ids> <stack-url>
```
Arguments:
- manage-token (required) Manage API token for the stack.
- backend-ids (required) Comma-separated list of storage backend IDs to delete (e.g. `123,456,789`).
- stack-url (required) Full stack URL, e.g. https://connection.keboola.com.

Options:
- --force / -f Actually remove the backends. Without it the command runs in dry-run mode and only lists what would be removed.

Behavior:
- Lists all storage backends on the stack.
- For each requested ID: skips it (with a message) when no such backend exists; otherwise prints the backend host and owner and (with --force) removes it via the Manage API.

## Reset Workspace passwords for projects in an organization
This command is rather specific to BYODB snowflake backend migration.
It resets all legacy (not keypair type) Snowflake workspace passwords for all projects in an organization.
Expand Down
2 changes: 2 additions & 0 deletions cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use Keboola\Console\Command\AddFeature;
use Keboola\Console\Command\AllStacksIterator;
use Keboola\Console\Command\DeleteStorageBackend;
use Keboola\Console\Command\DeleteOrganizationOrphanedWorkspaces;
use Keboola\Console\Command\DeleteOrganizationOwnerlessWorkspaces;
use Keboola\Console\Command\DeleteOrphanedWorkspaces;
Expand Down Expand Up @@ -57,4 +58,5 @@
$application->add(new UpdateDataRetention());
$application->add(new OrganizationResetWorkspacePasswords());
$application->add(new OrganizationsAddFeature());
$application->add(new DeleteStorageBackend());
$application->run();
73 changes: 73 additions & 0 deletions src/Keboola/Console/Command/DeleteStorageBackend.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

namespace Keboola\Console\Command;

use Keboola\ManageApi\Client;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class DeleteStorageBackend extends Command
{
protected function configure(): void
{
$this
->setName('manage:delete-backend')
->setDescription('Delete storage backends from a stack by their IDs. Dry-run by default.')
->addArgument('token', InputArgument::REQUIRED, 'manage api token')
->addArgument('ids', InputArgument::REQUIRED, 'list of storage backend IDs separated by a comma')
->addArgument('url', InputArgument::REQUIRED, 'Stack URL')
->addOption('force', 'f', InputOption::VALUE_NONE, 'Will actually do the work, otherwise it\'s dry run');
}

protected function execute(InputInterface $input, OutputInterface $output): int
{
$apiToken = $input->getArgument('token');
assert(is_string($apiToken));
$apiUrl = $input->getArgument('url');
assert(is_string($apiUrl));
$ids = $input->getArgument('ids');
assert(is_string($ids));
$force = (bool) $input->getOption('force');
$output->writeln($force ? 'DANGER: Using force mode! Backend will be removed.' : 'DRY RUN');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving the banner wording as-is for this PR. The dry-run path already prints a clear DRY RUN banner and the force path is intentionally loud (DANGER: Using force mode!), so the destructive intent is explicit. Happy to revisit if we standardize the wording across commands.


$client = $this->createClient($apiUrl, $apiToken);

$allBackends = $client->listStorageBackend();
$allBackendsAssociative = [];
foreach ($allBackends as $backend) {
$allBackendsAssociative[$backend['id']] = $backend;
}
$backendIds = array_filter(array_map('trim', explode(',', $ids)), 'is_numeric');
foreach ($backendIds as $id) {
if (!array_key_exists($id, $allBackendsAssociative)) {
$output->writeln(sprintf('Backend with ID "%s" does not exist, skipping...', $id));
continue;
}
$output->write(sprintf(
'Removing backend "%s" (%s) by "%s" - ',
$id,
$allBackendsAssociative[$id]['host'],
$allBackendsAssociative[$id]['owner']
));
if ($force) {
$output->writeln('really');
$client->removeStorageBackend((int) $id);
} else {
$output->writeln('just kidding - dry mode');
}
}

return 0;
}

private function createClient(string $host, string $token): Client
{
return new Client([
'url' => $host,
'token' => $token,
]);
}
}