Skip to content

Commit

Permalink
Merge pull request #30 from WeareJH/JDTB-46-keep-config-values-or-tables
Browse files Browse the repository at this point in the history
JDTB-46 Allow to keep core_config_data or cache certain config values
  • Loading branch information
maciejslawik committed Aug 14, 2024
2 parents 98d31e3 + 305cf4c commit 644917e
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 5 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,22 @@ reimport them
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME
```

To skip admin accounts backup
#### To skip admin accounts backup

```
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME --no-admin-backup=1
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME --no-admin-backup=1
```

#### Config backup

The `config-backup` option accepts 3 values:
* *skip* - skips the backup of local config and imports everything from the remote
* *merge* - backs up only the paths configured under `stripped_db_provider/dump/config_paths_keep` (accepts MySQL wildcards `%`),
imports everything from the remote and merges the backed up config with the remote config
* *preserve-local* - backs up the whole `core_config_data` and restores it after the DB import from remote

```
bin/magento wearejh:stripped-db-provider:import-from-remote PROJECT NAME --config-backup=merge
```

## Issues / Feature Request
Expand Down
43 changes: 42 additions & 1 deletion src/Console/ImportFromRemoteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ class ImportFromRemoteCommand extends Command
{
private const ARGUMENT_PROJECT_NAME = 'source-project-name';
private const OPTION_NO_ADMIN_ACCOUNT_BACKUP = 'no-admin-backup';
private const OPTION_CONFIG_DATA_BACKUP = 'config-backup';

private CONST VALUE_CONFIG_SKIP = 'skip';
private CONST VALUE_CONFIG_PRESERVE = 'preserve-local';
private CONST VALUE_CONFIG_MERGE = 'merge';

private const SUCCESS = 1;

Expand Down Expand Up @@ -47,6 +52,13 @@ protected function configure()
'Set this flag to skip backup of local admin accounts',
false
);
$this->addOption(
self::OPTION_CONFIG_DATA_BACKUP,
null,
InputOption::VALUE_OPTIONAL,
'Set this flag to back up the whole core_config_data table',
self::VALUE_CONFIG_MERGE
);
}

/**
Expand All @@ -68,6 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
try {
$sourceProjectMeta = new ProjectMeta($input->getArgument(self::ARGUMENT_PROJECT_NAME));
$backupAdminAccounts = !$input->getOption(self::OPTION_NO_ADMIN_ACCOUNT_BACKUP);
$backupConfig = $this->getConfigBackupOption($input);

$output->writeln('<fg=cyan;options=bold>Downloading Database From Cloud Storage...</>');
$this->dbFacade->downloadDatabaseDump($sourceProjectMeta);
Expand All @@ -84,6 +97,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$this->dbFacade->backupLocalAdminAccounts($sourceProjectMeta);
}

if ($backupConfig === self::VALUE_CONFIG_PRESERVE) {
$output->writeln('<fg=cyan;options=bold>Backing up config ...</>');
$this->dbFacade->backupLocalConfig($sourceProjectMeta);
} else if ($backupConfig === self::VALUE_CONFIG_MERGE) {
$output->writeln('<fg=cyan;options=bold>Backing up preconfigured config paths ...</>');
$this->dbFacade->backupConfigValues($sourceProjectMeta);
}

$output->writeln("<info>Starting the Database import</info>");
$this->dbFacade->importDatabaseDump($sourceProjectMeta);
$output->writeln("<info>Database successfully imported.</info>");
Expand All @@ -92,17 +113,37 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$output->writeln('<fg=cyan;options=bold>Restoring local admin accounts ...</>');
$this->dbFacade->restoreLocalAdminAccountsFromBackup($sourceProjectMeta);
}

if ($backupConfig === self::VALUE_CONFIG_PRESERVE) {
$output->writeln('<fg=cyan;options=bold>Restoring config ...</>');
$this->dbFacade->restoreLocalConfigFromBackup($sourceProjectMeta);
} else if ($backupConfig === self::VALUE_CONFIG_MERGE) {
$output->writeln('<fg=cyan;options=bold>Restoring preconfigured config paths ...</>');
$this->dbFacade->restoreConfigValues();
}
} catch (Exception $e) {
$output->writeln("<error>{$e->getMessage()}</error>");
} finally {
if (isset($sourceProjectMeta)) {
$this->dbFacade->cleanUpLocalDumpFiles($sourceProjectMeta);
}
if ($backupAdminAccounts) {
if (isset($backupAdminAccounts) && $backupAdminAccounts) {
$this->dbFacade->cleanUpAdminAccountsBackup($sourceProjectMeta);
}
if (isset($backupConfig) && $backupConfig === self::VALUE_CONFIG_PRESERVE) {
$this->dbFacade->cleanUpConfigBackup($sourceProjectMeta);
}
}

return self::SUCCESS;
}

private function getConfigBackupOption(InputInterface $input): string
{
$configBackupOption = $input->getOption(self::OPTION_CONFIG_DATA_BACKUP);
if (!in_array($configBackupOption, [self::VALUE_CONFIG_SKIP, self::VALUE_CONFIG_PRESERVE, self::VALUE_CONFIG_MERGE])) {
$configBackupOption = self::VALUE_CONFIG_MERGE;
}
return $configBackupOption;
}
}
11 changes: 11 additions & 0 deletions src/Model/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Config
* Dump Specific
*/
const XML_PATH_PROJECT_IGNORE_TABLES = 'stripped_db_provider/dump/project_ignore_tables';
const XML_PATH_PROJECT_KEEP_CONFIG_PATHS = 'stripped_db_provider/dump/config_paths_keep';

public function __construct(
private readonly ScopeConfigInterface $config,
Expand Down Expand Up @@ -77,4 +78,14 @@ public function getLocalDbConfigData(string $key): ?string
)
);
}

public function getConfigPathsToKeep(): array
{;
$defaultPaths = explode(
',',
(string) $this->config->getValue(self::XML_PATH_PROJECT_KEEP_CONFIG_PATHS)
);

return array_merge($defaultPaths, $projectIgnoredPaths);
}
}
2 changes: 1 addition & 1 deletion src/Model/Db/DbAdminAccountsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function restoreAdminAccountsBackup(ProjectMeta $projectMeta): void
"mysql:host={$hostName};dbname={$dbName}",
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_USER),
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_PASSWORD),
['skip-definer' => true]
['skip-definer' => true, 'add-drop-table' => true, 'skip-triggers' => true]
);
$dumper->restore($this->getAdminAccountsBackupFilePath($projectMeta));
}
Expand Down
101 changes: 101 additions & 0 deletions src/Model/Db/DbConfigBackupManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

declare(strict_types=1);

namespace Jh\StrippedDbProvider\Model\Db;

use Ifsnop\Mysqldump\Mysqldump;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Config\ConfigOptionsListConstants;
use Jh\StrippedDbProvider\Model\Config;
use Jh\StrippedDbProvider\Model\ProjectMeta;
use Magento\Framework\Shell;

class DbConfigBackupManager
{
private const BACKUP_FILENAME = 'core_config_data.sql';

public function __construct(
private Config $config,
private Shell $shell,
private ResourceConnection $resourceConnection,
private array $configCache = []
) {
}

/**
* @throws \Exception
*/
public function backupConfig(ProjectMeta $projectMeta): void
{
$hostName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_HOST);
$dbName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_NAME);
$dumper = new Mysqldump(
"mysql:host={$hostName};dbname={$dbName}",
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_USER),
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_PASSWORD),
[
'skip-definer' => true,
'add-drop-table' => true,
'include-tables' => [
'core_config_data'
]
]
);

$dumper->start($this->getConfigBackupFilePath($projectMeta));
}

public function restoreConfigBackup(ProjectMeta $projectMeta): void
{
$hostName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_HOST);
$dbName = $this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_NAME);
$dumper = new Mysqldump(
"mysql:host={$hostName};dbname={$dbName}",
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_USER),
$this->config->getLocalDbConfigData(ConfigOptionsListConstants::KEY_PASSWORD),
['skip-definer' => true, 'add-drop-table' => true, 'skip-triggers' => true]
);
$dumper->restore($this->getConfigBackupFilePath($projectMeta));
}

public function cleanUp(ProjectMeta $projectMeta): void
{
try {
$this->shell->execute("rm %s", [$this->getConfigBackupFilePath($projectMeta)]);
} catch (\Exception $e) {
//empty
}
}

public function cacheConfigValuesToKeep(): void
{
$pathsToCache = $this->config->getConfigPathsToKeep();
$connection = $this->resourceConnection->getConnection();
$tableName = $this->resourceConnection->getTableName('core_config_data');

$select = $connection->select()
->from($tableName,['*']);

foreach ($pathsToCache as $pattern) {
$select->orWhere('path LIKE ?', $pattern);
}

$this->configCache = $connection->fetchAll($select);
}

public function restoreConfigValuesToKeep(): void
{
foreach ($this->configCache as $config) {
$this->resourceConnection->getConnection()->insertOnDuplicate(
$this->resourceConnection->getTableName('core_config_data'),
$config
);
}
}

private function getConfigBackupFilePath(ProjectMeta $projectMeta): string
{
return $projectMeta->getLocalDumpStoragePath() . self::BACKUP_FILENAME;
}
}
28 changes: 27 additions & 1 deletion src/Model/DbFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ public function __construct(
private Db\DbUploader $uploader,
private Db\DbImporter $importer,
private Db\DbCleaner $cleaner,
private Db\DbAdminAccountsManager $adminAccountsManager
private Db\DbAdminAccountsManager $adminAccountsManager,
private Db\DbConfigBackupManager $configBackupManager
) {
}

Expand Down Expand Up @@ -83,4 +84,29 @@ public function cleanUpAdminAccountsBackup(ProjectMeta $projectMeta): void
{
$this->adminAccountsManager->cleanUp($projectMeta);
}

public function backupLocalConfig(ProjectMeta $projectMeta): void
{
$this->configBackupManager->backupConfig($projectMeta);
}

public function restoreLocalConfigFromBackup(ProjectMeta $projectMeta): void
{
$this->configBackupManager->restoreConfigBackup($projectMeta);
}

public function cleanUpConfigBackup(ProjectMeta $projectMeta): void
{
$this->configBackupManager->cleanUp($projectMeta);
}

public function backupConfigValues(): void
{
$this->configBackupManager->cacheConfigValuesToKeep();
}

public function restoreConfigValues(): void
{
$this->configBackupManager->restoreConfigValuesToKeep();
}
}
3 changes: 3 additions & 0 deletions src/etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
<secret_access_key backend_model="Magento\Config\Model\Config\Backend\Encrypted"></secret_access_key>
<access_key_id backend_model="Magento\Config\Model\Config\Backend\Encrypted"></access_key_id>
</storage>
<dump>
<config_paths_keep>payment/%</config_paths_keep>
</dump>
</stripped_db_provider>
</default>
</config>

0 comments on commit 644917e

Please sign in to comment.