Skip to content

Commit

Permalink
MariaDB - Add backupper and restorer (#77)
Browse files Browse the repository at this point in the history
* noissue - MariaDB - Add backupper and restorer

* noissue - MariaDB - Add backupper and restorer

* remove unwanted modification

* Check backup file can be read

* fix configuration examples

* fix configuration examples
  • Loading branch information
SimonMellerin committed Dec 20, 2023
1 parent 4876743 commit 4eb6a93
Show file tree
Hide file tree
Showing 11 changed files with 234 additions and 21 deletions.
14 changes: 8 additions & 6 deletions config/packages/db_tools.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ db_tools:
# Specify here paths to binaries, only if the system can't find them by himself
# platform are 'mysql', 'postgresql', 'sqlite'
#backupper_binaries:
#postgresql: 'usr/bin/pg_dump' # default 'pg_dump'
#mysql: 'usr/bin/mysqldump' # default 'mysqldump'
#sqlite: 'usr/bin/sqlite3' # default 'sqlite3'
#mariadb: '/usr/bin/mariadb-dump' # default 'mariadb-dump'
#mysql: '/usr/bin/mysqldump' # default 'mysqldump'
#postgresql: '/usr/bin/pg_dump' # default 'pg_dump'
#sqlite: '/usr/bin/sqlite3' # default 'sqlite3'
#restorer_binaries:
#postgresql: 'usr/bin/pg_restore' # default 'pg_restore'
#mysql: 'usr/bin/mysql' # default 'mysql'
#sqlite3: 'usr/bin/sqlite3' # default 'sqlite3'
#mariadb: '/usr/bin/mariadb' # default 'mariadb'
#mysql: '/usr/bin/mysql' # default 'mysql'
#postgresql: '/usr/bin/pg_restore' # default 'pg_restore'
#sqlite: '/usr/bin/sqlite3' # default 'sqlite3'

# Update this configuration if you want to look for anonymizers in a custom folder.
# These are default paths that will always be registered even if you override the
Expand Down
17 changes: 10 additions & 7 deletions docs/content/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,9 @@ db_tools:

`db-tools:backup` and `db-tools:restore` need your system/environment to provide some extra binaries
to be able to work. These binaries depend on the database vendor you use, you will need:
* for PostgreSQL: `pg_dump` and `pg_restore`
* for MariaDB: `mariadb-dump` and `mariadb`
* for MySQL: `mysqldump` and `mysql`
* for PostgreSQL: `pg_dump` and `pg_restore`
* for SQLite: `sqlite3`

You can verify that binaries for your DBAL connection(s) are correctly found by the *DbToolsBundle* launching:
Expand All @@ -93,13 +94,15 @@ If the `db-tools:check` command returns you some errors:
# Specify here paths to binaries, only if the system can't find them by himself
# platform are 'mysql', 'postgresql', 'sqlite'
backupper_binaries:
postgresql: 'usr/bin/pg_dump' # default 'pg_dump'
mysql: 'usr/bin/mysqldump' # default 'mysqldump'
sqlite: 'usr/bin/sqlite3' # default 'sqlite3'
mariadb: '/usr/bin/mariadb-dump' # default 'mariadb-dump'
mysql: '/usr/bin/mysqldump' # default 'mysqldump'
postgresql: '/usr/bin/pg_dump' # default 'pg_dump'
sqlite: '/usr/bin/sqlite3' # default 'sqlite3'
restorer_binaries:
postgresql: 'usr/bin/pg_restore' # default 'pg_restore'
mysql: 'usr/bin/mysql' # default 'mysql'
sqlite: 'usr/bin/sqlite3' # default 'sqlite3'
mariadb: '/usr/bin/mariadb' # default 'mariadb'
mysql: '/usr/bin/mysql' # default 'mysql'
postgresql: '/usr/bin/pg_restore' # default 'pg_restore'
sqlite: '/usr/bin/sqlite3' # default 'sqlite3'

#...
```
Expand Down
2 changes: 1 addition & 1 deletion docs/content/getting-started/database-vendors.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Here is a matrix of the current state of support:
|----------------------------|----------------|---------------|-------------|
| PostgreSQL | <Badge type="tip" text="" title="Working"/> | <Badge type="tip" text="" title="Working"/> | <Badge type="tip" text="" title="Working"/> |
| MySQL | <Badge type="tip" text="" title="Working"/> | <Badge type="tip" text="" title="Working"/> | <Badge type="tip" text="" title="Working"/> |
| MariaDB | <Badge type="danger" text="" title="Unsupported"/> | <Badge type="tip" text="" title="Working"/> | <Badge type="tip" text="" title="Working"/> |
| MariaDB | <Badge type="tip" text="" title="Working"/> | <Badge type="tip" text="" title="Working"/> | <Badge type="tip" text="" title="Working"/> |
| SQLite | <Badge type="tip" text="" title="Working"/> | <Badge type="warning" text="~" title="Only unit-tested"/> | <Badge type="danger" text="" title="Unsupported"/> |
| SQL Server | <Badge type="danger" text="" title="Unsupported"/> | <Badge type="warning" text="~" title="Only unit-tested"/> | <Badge type="danger" text="" title="Unsupported"/> |

Expand Down
3 changes: 2 additions & 1 deletion src/Backupper/BackupperFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ public function create(?string $connectionName = null): AbstractBackupper
$platform = $queryBuilder->getServerFlavor();

$backupper = match ($platform) {
Platform::POSTGRESQL => PgSQL\Backupper::class,
Platform::MARIADB => MariaDB\Backupper::class,
Platform::MYSQL => MySQL\Backupper::class,
Platform::POSTGRESQL => PgSQL\Backupper::class,
Platform::SQLITE => SQLite\Backupper::class,
default => throw new NotImplementedException(\sprintf(
"Backup is not implemented or configured for platform '%s' while using connection '%s'",
Expand Down
93 changes: 93 additions & 0 deletions src/Backupper/MariaDB/Backupper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

declare(strict_types=1);

namespace MakinaCorpus\DbToolsBundle\Backupper\MariaDB;

use MakinaCorpus\DbToolsBundle\Backupper\AbstractBackupper;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

class Backupper extends AbstractBackupper
{
private ?Process $process = null;

/**
* {@inheritdoc}
*/
public function startBackup(): self
{
$dbParams = $this->connection->getParams();

$args = [
$this->binary,
];

if (isset($dbParams['host'])) {
$args[] = '-h';
$args[] = $dbParams['host'];
}

if (isset($dbParams['user'])) {
$args[] = '-u';
$args[] = $dbParams['user'];
}

if (isset($dbParams['port'])) {
$args[] = '-P';
$args[] = $dbParams['port'];
}

if (isset($dbParams['password'])) {
$args[] = '-p' . $dbParams['password'];
}

$args[] = '-r';
$args[] = $this->destination;
$args[] = $dbParams['dbname'];
$args[] = '--no-tablespaces';

foreach ($this->excludedTables as $table) {
$args[] = '--ignore-table';
$args[] = $dbParams['dbname'] . '.' . $table;
}

if ($this->verbose) {
$args[] = '-v';
}

$this->process = new Process(
$args,
null,
null,
null,
600
);

$this->process->start();

return $this;
}

public function checkSuccessful(): void
{
if (!$this->process->isSuccessful()) {
throw new ProcessFailedException($this->process);
}
}

public function getExtension(): string
{
return 'sql';
}

public function getOutput(): string
{
return $this->process->getOutput();
}

public function getIterator(): \Traversable
{
return $this->process;
}
}
6 changes: 4 additions & 2 deletions src/DependencyInjection/DbToolsConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,18 @@ public function getConfigTreeBuilder(): TreeBuilder
->end()
->arrayNode('backupper_binaries')
->defaultValue([
'postgresql' => 'pg_dump',
'mariadb' => 'mariadb-dump',
'mysql' => 'mysqldump',
'postgresql' => 'pg_dump',
'sqlite' => 'sqlite3',
])
->scalarPrototype()->end()
->end()
->arrayNode('restorer_binaries')
->defaultValue([
'postgresql' => 'pg_restore',
'mariadb' => 'mariadb',
'mysql' => 'mysql',
'postgresql' => 'pg_restore',
'sqlite' => 'sqlite3',
])
->scalarPrototype()->end()
Expand Down
96 changes: 96 additions & 0 deletions src/Restorer/MariaDB/Restorer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

declare(strict_types=1);

namespace MakinaCorpus\DbToolsBundle\Restorer\MariaDB;

use MakinaCorpus\DbToolsBundle\Restorer\AbstractRestorer;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

class Restorer extends AbstractRestorer
{
private ?Process $process = null;
private mixed $backupStream = null;
/**
* {@inheritdoc}
*/
public function startRestore(): self
{
$dbParams = $this->connection->getParams();

$args = [
$this->binary,
];

if (isset($dbParams['host'])) {
$args[] = '-h';
$args[] = $dbParams['host'];
}

if (isset($dbParams['user'])) {
$args[] = '-u';
$args[] = $dbParams['user'];
}

if (isset($dbParams['port'])) {
$args[] = '-P';
$args[] = $dbParams['port'];
}

if (isset($dbParams['password'])) {
$args[] = '-p' . $dbParams['password'];
}

$args[] = $dbParams['dbname'];

if ($this->verbose) {
$args[] = '-v';
}

$this->backupStream = \fopen($this->backupFilename, 'r');

if (false === $this->backupStream) {
throw new \InvalidArgumentException(\sprintf(
"Backup file '%s' can't be read",
$this->backupFilename
));
}

$this->process = new Process(
$args,
null,
null,
$this->backupStream,
1800
);

$this->process->start();

return $this;
}

public function checkSuccessful(): void
{
if (!$this->process->isSuccessful()) {
throw new ProcessFailedException($this->process);
}

\fclose($this->backupStream);
}

public function getExtension(): string
{
return 'sql';
}

public function getOutput(): string
{
return $this->process->getOutput();
}

public function getIterator(): \Traversable
{
return $this->process;
}
}
8 changes: 7 additions & 1 deletion src/Restorer/MySQL/Restorer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use MakinaCorpus\DbToolsBundle\Restorer\AbstractRestorer;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\InputStream;
use Symfony\Component\Process\Process;

class Restorer extends AbstractRestorer
Expand Down Expand Up @@ -51,6 +50,13 @@ public function startRestore(): self

$this->backupStream = \fopen($this->backupFilename, 'r');

if (false === $this->backupStream) {
throw new \InvalidArgumentException(\sprintf(
"Backup file '%s' can't be read",
$this->backupFilename
));
}

$this->process = new Process(
$args,
null,
Expand Down
3 changes: 2 additions & 1 deletion src/Restorer/RestorerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ public function create(?string $connectionName = null): AbstractRestorer
$platform = $queryBuilder->getServerFlavor();

$restorer = match ($platform) {
Platform::POSTGRESQL => PgSQL\Restorer::class,
Platform::MARIADB => MariaDB\Restorer::class,
Platform::MYSQL => MySQL\Restorer::class,
Platform::POSTGRESQL => PgSQL\Restorer::class,
Platform::SQLITE => SQLite\Restorer::class,
default => throw new NotImplementedException(\sprintf(
"Restore is not implemented or configured for platform '%s' while using connection '%s'",
Expand Down
7 changes: 7 additions & 0 deletions src/Restorer/SQLite/Restorer.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ public function startRestore(): self
$command .= ' < "' . \addcslashes($this->backupFilename, '\\"') . '"';
$this->backupStream = \fopen($this->backupFilename, 'r');

if (false === $this->backupStream) {
throw new \InvalidArgumentException(\sprintf(
"Backup file '%s' can't be read",
$this->backupFilename
));
}

$this->process = Process::fromShellCommandline(
$command,
null,
Expand Down
6 changes: 4 additions & 2 deletions tests/Functional/BackupperRestorer/BackupperRestorerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ public function testBackupper(): void
;

$backupperFactoy = new BackupperFactory($mockDoctrineRegistry, [
'postgresql' => 'pg_dump',
'mariadb' => 'mariadb-dump',
'mysql' => 'mysqldump',
'postgresql' => 'pg_dump',
'sqlite' => 'sqlite3',
]);

Expand Down Expand Up @@ -130,8 +131,9 @@ public function testRestorer(): void
;

$restorerFactoy = new RestorerFactory($mockDoctrineRegistry, [
'postgresql' => 'pg_restore',
'mariadb' => 'mariadb',
'mysql' => 'mysql',
'postgresql' => 'pg_restore',
'sqlite' => 'sqlite3',
]);

Expand Down

0 comments on commit 4eb6a93

Please sign in to comment.