Skip to content

Commit 85ea231

Browse files
author
Yevhen Miroshnychenko
authored
Merge pull request #367 from magento-thunder/MAGECLOUD-2736
MAGECLOUD-2736: Magento can't install with custom DB configuration on cloud
2 parents fb28308 + 179445f commit 85ea231

29 files changed

+1342
-735
lines changed

src/App/Container.php

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,21 @@
1010
use Magento\MagentoCloud\Command\DbDump;
1111
use Magento\MagentoCloud\Command\Deploy;
1212
use Magento\MagentoCloud\Command\PostDeploy;
13-
use Magento\MagentoCloud\Config\ValidatorInterface;
13+
use Magento\MagentoCloud\Config\Database\ConfigInterface;
14+
use Magento\MagentoCloud\Config\Database\MergedConfig;
1415
use Magento\MagentoCloud\Config\Validator as ConfigValidator;
15-
use Magento\MagentoCloud\DB\Data\ConnectionInterface;
16-
use Magento\MagentoCloud\DB\Data\ReadConnection;
16+
use Magento\MagentoCloud\Config\ValidatorInterface;
1717
use Magento\MagentoCloud\Filesystem\DirectoryCopier;
1818
use Magento\MagentoCloud\Filesystem\DirectoryList;
1919
use Magento\MagentoCloud\Filesystem\FileList;
2020
use Magento\MagentoCloud\Filesystem\Flag;
2121
use Magento\MagentoCloud\Filesystem\SystemList;
22-
use Magento\MagentoCloud\Process\ProcessInterface;
23-
use Magento\MagentoCloud\Process\ProcessComposite;
2422
use Magento\MagentoCloud\Process\Build as BuildProcess;
2523
use Magento\MagentoCloud\Process\DbDump as DbDumpProcess;
2624
use Magento\MagentoCloud\Process\Deploy as DeployProcess;
2725
use Magento\MagentoCloud\Process\PostDeploy as PostDeployProcess;
26+
use Magento\MagentoCloud\Process\ProcessComposite;
27+
use Magento\MagentoCloud\Process\ProcessInterface;
2828

2929
/**
3030
* @inheritdoc
@@ -235,8 +235,8 @@ function () {
235235
$this->container->make(\Magento\MagentoCloud\Process\ValidateConfiguration::class, [
236236
'validators' => [
237237
ValidatorInterface::LEVEL_CRITICAL => [
238-
$this->container->make(ConfigValidator\Deploy\AdminEmail::class),
239238
$this->container->make(ConfigValidator\Deploy\DatabaseConfiguration::class),
239+
$this->container->make(ConfigValidator\Deploy\AdminEmail::class),
240240
$this->container->make(ConfigValidator\Deploy\SessionConfiguration::class),
241241
],
242242
ValidatorInterface::LEVEL_WARNING => [
@@ -316,9 +316,6 @@ function () {
316316
],
317317
]);
318318
});
319-
$this->container->when(DeployProcess\InstallUpdate\ConfigUpdate\Db\SlaveConfig::class)
320-
->needs(ConnectionInterface::class)
321-
->give(ReadConnection::class);
322319
$this->container->when(DeployProcess\InstallUpdate\ConfigUpdate\Urls::class)
323320
->needs(ProcessInterface::class)
324321
->give(function () {
@@ -361,9 +358,6 @@ function () {
361358
],
362359
]);
363360
});
364-
$this->container->when(\Magento\MagentoCloud\DB\Dump::class)
365-
->needs(ConnectionInterface::class)
366-
->give(ReadConnection::class);
367361
$this->container->when(PostDeploy::class)
368362
->needs(ProcessInterface::class)
369363
->give(function () {
@@ -387,6 +381,8 @@ function () {
387381
$this->container->when(CronKill::class)
388382
->needs(ProcessInterface::class)
389383
->give(DeployProcess\CronProcessKill::class);
384+
385+
$this->container->singleton(ConfigInterface::class, MergedConfig::class);
390386
}
391387

392388
/**
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\MagentoCloud\Config\Database;
7+
8+
/**
9+
* Interface for final database configuration.
10+
*/
11+
interface ConfigInterface
12+
{
13+
/**
14+
* Returns database configuration.
15+
*
16+
* @return array
17+
*/
18+
public function get(): array;
19+
}

src/Config/Database/MergedConfig.php

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\MagentoCloud\Config\Database;
7+
8+
use Magento\MagentoCloud\Config\ConfigMerger;
9+
use Magento\MagentoCloud\Config\Deploy\Reader as ConfigReader;
10+
use Magento\MagentoCloud\Config\Stage\DeployInterface;
11+
use Magento\MagentoCloud\DB\Data\ConnectionInterface;
12+
use Magento\MagentoCloud\DB\Data\RelationshipConnectionFactory;
13+
14+
/**
15+
* Returns merged final database configuration.
16+
*/
17+
class MergedConfig implements ConfigInterface
18+
{
19+
/**
20+
* Final configuration for deploy phase
21+
*
22+
* @var DeployInterface
23+
*/
24+
private $stageConfig;
25+
26+
/**
27+
* Configuration for slave connection
28+
*
29+
* @var SlaveConfig
30+
*/
31+
private $slaveConfig;
32+
33+
/**
34+
* Class for configuration merging
35+
*
36+
* @var ConfigMerger
37+
*/
38+
private $configMerger;
39+
40+
/**
41+
* Connection data from relationship array
42+
*
43+
* @var ConnectionInterface
44+
*/
45+
private $connectionData;
46+
47+
/**
48+
* Reader for app/etc/env.php file
49+
*
50+
* @var ConfigReader
51+
*/
52+
private $configReader;
53+
54+
/**
55+
* Final database configuration after merging
56+
*
57+
* @var array
58+
*/
59+
private $mergedConfig;
60+
61+
/**
62+
* @param RelationshipConnectionFactory $connectionFactory
63+
* @param ConfigReader $configReader
64+
* @param SlaveConfig $slaveConfig
65+
* @param DeployInterface $stageConfig
66+
* @param ConfigMerger $configMerger
67+
*/
68+
public function __construct(
69+
RelationshipConnectionFactory $connectionFactory,
70+
ConfigReader $configReader,
71+
SlaveConfig $slaveConfig,
72+
DeployInterface $stageConfig,
73+
ConfigMerger $configMerger
74+
) {
75+
$this->connectionData = $connectionFactory->create(RelationshipConnectionFactory::CONNECTION_MAIN);
76+
$this->configReader = $configReader;
77+
$this->slaveConfig = $slaveConfig;
78+
$this->stageConfig = $stageConfig;
79+
$this->configMerger = $configMerger;
80+
}
81+
82+
/**
83+
* Returns database configuration.
84+
*
85+
* @return array
86+
*/
87+
public function get(): array
88+
{
89+
if ($this->mergedConfig !== null) {
90+
return $this->mergedConfig;
91+
}
92+
93+
$envDbConfig = $this->stageConfig->get(DeployInterface::VAR_DATABASE_CONFIGURATION);
94+
95+
if (!$this->configMerger->isEmpty($envDbConfig) && !$this->configMerger->isMergeRequired($envDbConfig)) {
96+
return $this->mergedConfig = $this->configMerger->clear($envDbConfig);
97+
}
98+
99+
if (!empty($this->connectionData->getHost())) {
100+
$dbConfig = $this->generateDbConfig();
101+
} else {
102+
$dbConfig = $this->getDbConfigFromEnvFile();
103+
}
104+
105+
return $this->mergedConfig = $this->configMerger->mergeConfigs($dbConfig, $envDbConfig);
106+
}
107+
108+
/**
109+
* Generates database configuration from environment relationships.
110+
*
111+
* @param array envDbConfig
112+
* @return array
113+
*/
114+
private function generateDbConfig(): array
115+
{
116+
$connectionData = [
117+
'username' => $this->connectionData->getUser(),
118+
'host' => $this->connectionData->getHost(),
119+
'dbname' => $this->connectionData->getDbName(),
120+
'password' => $this->connectionData->getPassword(),
121+
];
122+
123+
$dbConfig = [
124+
'connection' => [
125+
'default' => $connectionData,
126+
'indexer' => $connectionData,
127+
],
128+
];
129+
130+
if ($this->stageConfig->get(DeployInterface::VAR_MYSQL_USE_SLAVE_CONNECTION)
131+
&& $this->isDbConfigurationCompatibleWithSlaveConnection()
132+
) {
133+
$slaveConfiguration = $this->slaveConfig->get();
134+
135+
if (!empty($slaveConfiguration)) {
136+
$dbConfig['slave_connection']['default'] = $slaveConfiguration;
137+
}
138+
}
139+
140+
return $dbConfig;
141+
}
142+
143+
/**
144+
* Checks that database configuration was changed in DATABASE_CONFIGURATION variable
145+
* in not compatible way with slave_connection.
146+
*
147+
* Returns true if $envDbConfig contains host or dbname for default connection
148+
* that doesn't match connection from relationships,
149+
* otherwise return false.
150+
*
151+
* @return boolean
152+
*/
153+
public function isDbConfigurationCompatibleWithSlaveConnection(): bool
154+
{
155+
$envDbConfig = $this->stageConfig->get(DeployInterface::VAR_DATABASE_CONFIGURATION);
156+
157+
if ((isset($envDbConfig['connection']['default']['host'])
158+
&& $envDbConfig['connection']['default']['host'] !== $this->connectionData->getHost())
159+
|| (isset($envDbConfig['connection']['default']['dbname'])
160+
&& $envDbConfig['connection']['default']['dbname'] !== $this->connectionData->getDbName())
161+
) {
162+
return false;
163+
}
164+
165+
return true;
166+
}
167+
168+
/**
169+
* Returns db configuration from env.php.
170+
*
171+
* This method is calling only in case when database relationship configuration doesn't exist and
172+
* database is not configured through .magento.env.yaml or env variable.
173+
* It's workaround for scenarios when magento was installed by raw setup:install command not by deploy scripts.
174+
*/
175+
private function getDbConfigFromEnvFile(): array
176+
{
177+
return $this->configReader->read()['db'] ?? [];
178+
}
179+
}

src/Config/Database/SlaveConfig.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\MagentoCloud\Config\Database;
7+
8+
use Magento\MagentoCloud\DB\Data\RelationshipConnectionFactory;
9+
10+
/**
11+
* Returns mysql slave connection
12+
*/
13+
class SlaveConfig implements ConfigInterface
14+
{
15+
/**
16+
* @var RelationshipConnectionFactory
17+
*/
18+
private $connectionFactory;
19+
20+
/**
21+
* @param RelationshipConnectionFactory $connectionFactory
22+
*/
23+
public function __construct(RelationshipConnectionFactory $connectionFactory)
24+
{
25+
$this->connectionFactory = $connectionFactory;
26+
}
27+
28+
/**
29+
* Returns mysql slave connection if database configuration is present in relationships
30+
* otherwise returns empty array.
31+
*
32+
* @return array
33+
*/
34+
public function get(): array
35+
{
36+
$slaveConnection = [];
37+
38+
$connectionData = $this->connectionFactory->create(RelationshipConnectionFactory::CONNECTION_SLAVE);
39+
if ($connectionData->getHost()) {
40+
$host = $connectionData->getHost();
41+
42+
if (!empty($connectionData->getPort())) {
43+
$host .= ':' . $connectionData->getPort();
44+
}
45+
46+
$slaveConnection = [
47+
'host' => $host,
48+
'username' => $connectionData->getUser(),
49+
'dbname' => $connectionData->getDBName(),
50+
'password' => $connectionData->getPassword(),
51+
'model' => 'mysql4',
52+
'engine' => 'innodb',
53+
'initStatements' => 'SET NAMES utf8;',
54+
'active' => '1',
55+
];
56+
}
57+
58+
return $slaveConnection;
59+
}
60+
}

src/Config/Deploy/Reader.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
use Magento\MagentoCloud\Filesystem\Reader\ReaderInterface;
1111

1212
/**
13-
* @inheritdoc
13+
* Reads configuration from /app/etc/env.php file
14+
*
15+
* {@inheritdoc}
1416
*/
1517
class Reader implements ReaderInterface
1618
{

src/Config/Environment.php

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -155,38 +155,6 @@ public function getAdminLocale(): string
155155
return $this->getVariables()['ADMIN_LOCALE'] ?? 'en_US';
156156
}
157157

158-
/**
159-
* @return string|float
160-
*/
161-
public function getDbHost()
162-
{
163-
return $this->getRelationship('database')[0]['host'] ?? '';
164-
}
165-
166-
/**
167-
* @return string
168-
*/
169-
public function getDbName(): string
170-
{
171-
return $this->getRelationship('database')[0]['path'] ?? '';
172-
}
173-
174-
/**
175-
* @return string
176-
*/
177-
public function getDbUser(): string
178-
{
179-
return $this->getRelationship('database')[0]['username'] ?? '';
180-
}
181-
182-
/**
183-
* @return string
184-
*/
185-
public function getDbPassword(): string
186-
{
187-
return $this->getRelationship('database')[0]['password'] ?? '';
188-
}
189-
190158
/**
191159
* @return string
192160
*/

0 commit comments

Comments
 (0)