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

Add remote docker-compose support with docker host (-H) for sql:sync and rsync #6213

Open
wants to merge 2 commits into
base: 13.x
Choose a base branch
from
Open
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
27 changes: 21 additions & 6 deletions src/Commands/core/RsyncCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,29 @@ public function rsync($source, $target, array $extra, $options = ['exclude-paths
throw new UserAbortException();
}
}

$rsync_options = $this->rsyncOptions($options);
$parameters = array_merge([$rsync_options], $extra);
$parameters[] = Escape::shellArg($this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash());
$parameters[] = Escape::shellArg($this->targetEvaluatedPath->fullyQualifiedPath());

$ssh_options = $this->getConfig()->get('ssh.options', '');
$exec = "rsync -e 'ssh $ssh_options'" . ' ' . implode(' ', array_filter($parameters));
$source_alias = $this->sourceEvaluatedPath->getSiteAlias();
$target_alias = $this->targetEvaluatedPath->getSiteAlias();
$remote_docker_alias = $source_alias->has('docker.host') ? $source_alias : ($target_alias->has('docker.host') ? $target_alias : null);
if ($remote_docker_alias) {
$docker_host = $remote_docker_alias->get('docker.host', '');
$docker_project = $remote_docker_alias->get('docker.project', '');
$parameters[] = $source_alias->has('docker.host') ?
$source_alias->get('docker.service') . ':' . Escape::shellArg($this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash()) :
Escape::shellArg($this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash());
$parameters[] = $target_alias->has('docker.host') ?
$target_alias->get('docker.service') . ':' . Escape::shellArg($this->targetEvaluatedPath->fullyQualifiedPath()) :
Escape::shellArg($this->targetEvaluatedPath->fullyQualifiedPath());
$compose_version = $remote_docker_alias->get('docker.compose.version', '1');
$docker_e = $compose_version == '1' ? "docker-compose -H $docker_host -p $docker_project" : "docker -H $docker_host compose -p $docker_project";
$exec = "rsync -e '$docker_e exec -i'" . ' ' . implode(' ', array_filter($parameters));
} else {
$ssh_options = $this->getConfig()->get('ssh.options', '');
$parameters[] = Escape::shellArg($this->sourceEvaluatedPath->fullyQualifiedPathPreservingTrailingSlash());
$parameters[] = Escape::shellArg($this->targetEvaluatedPath->fullyQualifiedPath());
$exec = "rsync -e 'ssh $ssh_options'" . ' ' . implode(' ', array_filter($parameters));
}
$process = $this->processManager()->shell($exec);
$process->run($process->showRealtime());

Expand Down
5 changes: 4 additions & 1 deletion src/Commands/sql/SqlSyncCommands.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,10 @@ public function rsync(array $options, SiteAlias $sourceRecord, SiteAlias $target
// Determine path/to/dump on target.
if ($options['target-dump']) {
$target_dump_path = $options['target-dump'];
} elseif (!$sourceRecord->isRemote() && !$targetRecord->isRemote()) {
} elseif (
!$sourceRecord->isRemote() && !$targetRecord->isRemote()
&& (!$targetRecord->has('docker.host') && !$sourceRecord->has('docker.host'))
) {
$target_dump_path = $source_dump_path;
$do_rsync = false;
} else {
Expand Down
51 changes: 51 additions & 0 deletions tests/functional/SqlSyncTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,57 @@ public function testSimulatedSqlSync()
$this->assertStringContainsString("[notice] Simulating: ssh -o PasswordAuthentication=no user@server '/path/to/vendor/bin/drush --no-interaction sql:sync @synctest.remote @synctest.local --uri=sitename'", $output);
}

public function testSimulatedDockerRemoteSqlSync()
{
if ($this->isWindows()) {
$this->markTestSkipped('On Windows, Paths mismatch and confuse rsync.');
}

$fixtureSites = [
'remote' => [
'docker' => [
'host' => 'ssh://www-admin@host',
'service' => 'php'
],
'paths' => [
'drush-script' => '/path/to/drush',
],
],
'local' => [
],
];
$this->setUpSettings($fixtureSites, 'synctest');
$options = [
'uri' => 'OMIT',
'simulate' => null,
'alias-path' => __DIR__ . '/resources/alias-fixtures',
// @todo Ensure that shortcuts are normalized to long option names https://github.com/drush-ops/drush/pull/4515.
'verbose' => null,
];

$expectedAliasPath = '--alias-path=__DIR__/resources/alias-fixtures';

// Test simulated simple rsync remote-to-local
$this->drush(SqlSyncCommands::SYNC, ['@synctest.remote', '@synctest.local'], $options, '@synctest.local');
$output = $this->getSimplifiedErrorOutput();
$this->assertStringContainsString("[notice] Simulating: docker-compose exec -T php /path/to/drush sql:dump --no-interaction --strict=0 --gzip --result-file=auto --format=json --uri=remote", $output);
$this->assertStringContainsString("[notice] Simulating: __DIR__/drush.php core:rsync @synctest.remote:/simulated/path/to/dump.tgz @synctest.local:__SANDBOX__/tmp/dump.tgz --yes --uri=local -- --remove-source-files", $output);
$this->assertStringContainsString("[notice] Simulating: __DIR__/drush.php sql:query --no-interaction --strict=0 --file=__SANDBOX__/tmp/dump.tgz --file-delete --uri=local", $output);


// Test simulated simple sql:sync local-to-remote
$this->drush(SqlSyncCommands::SYNC, ['@synctest.local', '@synctest.remote'], $options, '@synctest.local');
$output = $this->getSimplifiedErrorOutput();
$this->assertStringContainsString("[notice] Simulating: __DIR__/drush.php sql:dump --no-interaction --strict=0 --gzip --result-file=auto --format=json --uri=local", $output);
$this->assertStringContainsString("[notice] Simulating: __DIR__/drush.php core:rsync @synctest.local:/simulated/path/to/dump.tgz @synctest.remote:/tmp/dump.tgz --yes --uri=local -- --remove-source-files", $output);
$this->assertStringContainsString("[notice] Simulating: docker-compose exec -T php /path/to/drush sql:query --no-interaction --strict=0 --file=/tmp/dump.tgz --file-delete --uri=remote", $output);

// Test simulated remote invoke with a remote runner.
$this->drush(SqlSyncCommands::SYNC, ['@synctest.remote', '@synctest.local'], $options, 'user@server/path/to/drupal#sitename');
$output = $this->getSimplifiedErrorOutput();
$this->assertStringContainsString("[notice] Simulating: ssh -o PasswordAuthentication=no user@server '/path/to/vendor/bin/drush --no-interaction sql:sync @synctest.remote @synctest.local --uri=sitename'", $output);
}

/**
* Covers the following responsibilities.
* - A user created on the source site is copied to the destination site.
Expand Down
16 changes: 16 additions & 0 deletions tests/functional/resources/alias-fixtures/example.site.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,19 @@ live:
options: '-o PasswordAuthentication=example'
paths:
drush-script: '/example/path/to/drush'


stage-docker:
root: /path/to/stage
uri: stage
docker:
service: php
host: ssh://user@host
project: 'project'
compose:
version: 1
command:
core:
rsync:
options:
exclude-paths: stage-path
10 changes: 10 additions & 0 deletions tests/integration/RsyncIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ public function testRsyncSimulated()
$expected = "[notice] Simulating: rsync -e 'ssh ' -akz /path/to/stage /path/to/dev";
$this->assertErrorOutputContains($expected);

// Test source docker rsync with two local sites
$this->drush(RsyncCommands::RSYNC, ['@example.stage-docker', '@example.dev'], $options, self::EXIT_SUCCESS, '');
$expected = "[notice] Simulating: rsync -e 'docker-compose -H ssh://user@host -p project exec -i' -akz php:/path/to/stage /path/to/dev";
$this->assertErrorOutputContains($expected);

// Test source docker rsync with two local sites
$this->drush(RsyncCommands::RSYNC, ['@example.dev', '@example.stage-docker'], $options, self::EXIT_SUCCESS, '');
$expected = "[notice] Simulating: rsync -e 'docker-compose -H ssh://user@host -p project exec -i' -akz /path/to/dev php:/path/to/stage";
$this->assertErrorOutputContains($expected);

// Test simulated rsync with relative paths
$this->drush(RsyncCommands::RSYNC, ['@example.dev:files', '@example.stage:files'], $options, self::EXIT_SUCCESS, '');
$expected = "[notice] Simulating: rsync -e 'ssh ' -akz /path/to/dev/files /path/to/stage/files";
Expand Down