Problem/Motivation

We have two modules named "B" and "D" and two identical profiles named "A" and "C". Module "D" provides a filter.format.custom_format config. Module "B" provides a custom filter entity only.
The config filter.format_custom format is being overwritten in both profiles and contains the custom filter from module "B" and therefore has two module dependencies - to both "B" and "D".

The installation of profile "C" is successful.

The installation of profile "A" is unsuccessful.

During the installation of profile "A" the config installer throws the UnmetDependencyException because when trying to install module "D" the overwritten config from the profile is used and it contains a dependency to module "B", which isn't installed yet.

What I've observed is that because of the naming ModuleHandler::buildModuleDependencies() will sort the modules differently, which is not an actual problem because the dependencies are still being considered. However the dependencies of the overwritten configs are not being considered and what happens is that depending on the profile name in the case of profile "C" module "B" is installed before module "D" and in the case of profile "A" module "D" is installed before module "B". However in the second case during the installation of module "D" the config from the profile will be used and an unmet dependency will be detected, because the config from the profile has a dependency on both modules "B" and "D" and "B" isn't installed yet.

Considering this a major issue, because I couldn't think of a workaround and profile installation isn't possible.

Proposed resolution

During profile installation do not install each module with its default config taken from the profile config storage but from the module own config storage. When the profile itself is being installed then reinstall all the config contained in its own config storage.

Remaining tasks

User interface changes

API changes

Data model changes

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

hchonov created an issue. See original summary.

hchonov’s picture

I've talked with @tstoeckler about this issue and he offered two approaches:

  1. Install the modules with their default configs and later during the profile installation re-install the configs from the profile.
  2. If a config is being overwritten in the profile then skip importing it when installing a module and import it when installing the profile.

I personally think that the first solution is better because in this case the config will be accessible in hooks during the installation.

hchonov’s picture

Status: Active » Needs review
FileSize
13.13 KB

With the following changes made the problem from the issue summary has been solved.

hchonov’s picture

Providing a test for the problem from the issue summary.

The last submitted patch, 4: 2872977-4-test-only.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 4: 2872977-4.patch, failed testing.

hchonov’s picture

I've removed the extra test as there is already one failing test with the additions to the profile "testing_config_overrides". I also had to change the type of the config from config_object to config_entity, because otherwise the "dependencies" key is not defined in the schema.

Status: Needs review » Needs work

The last submitted patch, 7: 2872977-7-test-only.patch, failed testing.

hchonov’s picture

Status: Needs work » Needs review
FileSize
14.09 KB
5.09 KB

Actually we don't need the changes to the protected methods because we could just provide the profile storages argument with an empty array in case of an profile/site installation.

hchonov’s picture

FileSize
5.78 KB
8.16 KB

I've talked with @alexpott about this in IRC and he suggested that we could simply use ConfigInstaller::drupalInstallationAttempted() to determine if Drupal installation is currently running instead of carrying that information from the module installer to the config installer. This has simplified the patch a lot and reduced it only to the config installer, therefore the credit for this should go all to Alex!

Status: Needs review » Needs work

The last submitted patch, 10: 2872977-10.patch, failed testing.

hchonov’s picture

I don't fully understand why the test Drupal\config\Tests\ConfigInstallProfileUnmetDependenciesTest wasn't failing with the previous approach, but only with the current. But this is a good thing, because this test is testing exactly the behavior from the issue summary and it looks like this was the expected behavior. I guess at the time of implementing the test it made sense but now having a realistic use case like the one from the issue summary with the filter format config certainly demonstrates that we have to support building inter-module dependencies in overridden configs in the profile.

I've removed all the tests I've added and now the only test is ConfigInstallProfileUnmetDependenciesTest, which I had to adjust to the new excepted behavior.

Status: Needs review » Needs work

The last submitted patch, 12: 2872977-12-test-only.patch, failed testing.

hchonov’s picture

Status: Needs work » Needs review

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tstoeckler’s picture

Status: Needs review » Needs work
Issue tags: +Needs reroll

This one needs a reroll for #2978952: Deprecate Drupal\simpletest\InstallerTestBase, convert children to BTB.

Also did a review:

  1. +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
    @@ -117,19 +117,15 @@ public function installDefaultConfig($type, $name) {
    +      $profile_storages = $this->drupalInstallationAttempted() ? [] : $this->getProfileStorages($name);
    
    @@ -460,8 +456,10 @@ public function checkConfigurationToInstall($type, $name) {
    +    $profile_storages = $this->drupalInstallationAttempted() ? [] : $this->getProfileStorages($name);
    

    These are the only two usages of getProfileStorages() so I think it makes sense to move the check in there.

  2. +++ b/core/lib/Drupal/Core/Config/ConfigInstaller.php
    --- a/core/modules/config/src/Tests/ConfigInstallProfileUnmetDependenciesTest.php
    +++ b/core/modules/config/src/Tests/ConfigInstallProfileUnmetDependenciesTest.php
    

    I like the fix to the test coverage here, but it even though the previous test was accidentally testing broken behavior, we should still have a test that proves that a missing dependency is properly caught during installation.

Other than that looks good and I agree with the approach taken here. It's a bit unfortunate to have to install certain things twice, but I don't see any way we can keep the system in a valid state each step of the way during installation.

alexpott’s picture

There's another issue that tackles this problem differently and I think in a better way - see #2922417: Profile provided configuration entities can have unmeetable dependencies - that issue only results in the expected single write to configuration.

alexpott’s picture

Issue tags: +Configuration system
alexpott’s picture

Status: Needs work » Closed (duplicate)

In fact I'm convinced these are duplicate issues with pretty much the same approach apart from how the other one deals with simple configuration which I think is better. I would also argue that the other one has slightly better test coverage so going to plump for that issue even though this issue was opened a little bit earlier. Will credit @hchonov and @tstoeckler on that issue for their work here.