Problem/Motivation
It is important that we people sync configuration is done against the same codebase in both the target and source instance. People have been surprised that you can't sync configuration from Beta-13 to RC-3. This issue will get worse with contrib under active development. We also need to ensure that extensions are installed using the same version of the extension so that any install hooks are the same and we need this to be able to solve #2428045: Comparing active storage to install storage is problematic, install storage may change anytime without storing a copy of the original config in config - this way we can store it in state.
Proposed resolution
When we run update.php write the current versions of the extensions to core.extension. When we install an extension or run updates write the version to core.extension. When we update or install a module store the schema version in core.extension. Use this information to ensure that when we import a full site configuration the codebase and database are in the same state.
Remaining tasks
Review all of the UI text
User interface changes
Additional configuration import validation messages
API changes
None
Data model changes
Additional versions
key added to core.extensions. The key holds a list of installed extensions. For each extension the version at install time is stored plus the version the last time update.php is run. For modules, the schema is also stored.
Comment | File | Size | Author |
---|---|---|---|
#52 | 2628144-52.patch | 34.52 KB | Manuel Garcia |
#50 | 2628144-50.patch | 34.43 KB | alexpott |
#50 | 48-50-interdiff.txt | 5.81 KB | alexpott |
#48 | 2628144-48.patch | 34.05 KB | timmillwood |
Comments
Comment #2
alexpottSo here's recording the installation time versions... need to work out how to record the module version at export time. I think maybe we just need to record this as part of update.php.
Comment #4
alexpottStill need to add current version and schema checking to the validator... but now have got the info in
core.extension
and have an upgrade path - that needs testing.Comment #6
alexpottSchema fun...
Comment #7
alexpottAdd tests and validating that both the source and target site instances have the same versions of modules and that the installed schema version is the same.
Comment #8
alexpottComment #10
alexpottI love config schema - keeps me honest :)
Comment #12
alexpottFixing the tests...
Comment #13
swentel CreditAttribution: swentel commentedI love the idea of this patch. At first I thought there were some flaws in it, but after reading it 3 times it seems very solid
This will even remove the discipline that you now need but can missed easily when syncing from dev to live or the other way around - I even guess people will be 'annoyed' in the beginning at first when this patch lands. However, it will ensure config integrity (and data integrity too in the end).
Could probably use a comment, something like 'Only compare existing modules' version and schema'. I missed the variable name and array_intersect_key twice making me conclude this code had some very annoying consequences, but in the end it's not :)
same here
Interesting, I always thought that we defaulted to the current version of Drupal, but it's not (even in 7 it doesn't).
Which makes me wonder whether we should enforce modules to have a version number anyways, instead of 'None' which is kind of pointless to me, even for a custom module. Should probably be a different issue though.
Should we have an explicit test for clearing the module from versions ? I don't see one immediately (although I see unsets further down the patch) ?
Same for themes
This is tested twice in the same test file - unless I'm missing some context here.
Comment #14
alexpottThanks for the review @swentel.
8.y.x-unknown
as we know the major version. Perhaps this should be split off to a precursor to discuss butnone
is also true.Comment #15
alexpottNeeds tests
Comment #18
alexpottHere an upgrade path test.
I also think we should have explicit tests for the update system changes so leaving the "Needs tests" tag on .
Comment #19
alexpottHere's a test for the changes to
drupal_set_installed_schema_version()
Comment #21
alexpottHmmm oh yeah schema needs to be a string... because that is the documented return value of...
Comment #23
alexpottDrupal\aggregator\Tests\AddFeedTest
passes fine locally... drupalci?Comment #24
alexpottI've been think about the install information. I think this might be a bit restrictive. Consider creating a site from config - it could make it impossible as the install and current versions don't match. So I think this should be removed.
Comment #25
alexpottRemoved the installed information.
Comment #27
alexpottFixing the test fail and making sure the update works as expected.
Comment #28
swentel CreditAttribution: swentel commentedTwo things that don't bother me, just pasting them here though for reference.
just for more clarity, something like 'Currently installed extension version' ? No biggy though.
Somehow I started quoting 'There will be blood' to myself. Not sure if we really need this comment here.
Other than that, this looks ready to me. Not sure if we want more eyes on this. I can RTBC it so other commiters can take a look at it or so you can all discuss it at least ?
Comment #29
davidwbarratt CreditAttribution: davidwbarratt at Golf Channel commentedIf I understand this issue correctly, this will force users to execute
updb
before runningconfig-import
.I like this (it should be one way or the other, I don't care which).
However, what if I need to write an update that requires the config import to have been run? For instance, what if my config creates an entity bundle, and then my update script creates a new entity of that bundle?
Comment #30
alexpottThis would be doing it wrong - if a module update creates an entity of a bundle that it itself does not provide it has to handle what would occur of those dependencies are missing. This is (imo) totally separate from the issue of importing config.
Comment #31
dawehnerIn general I would like to see how this affects work on multiple feature branches on your project. I almost always switch between feature branches, then do a
drush cim
and continue. When any branch would have had database updates applied, I would rather have to use DB dumps to switch branches? I just try to understand what this would mean on a day to day workflow.Should we mention to run update.php?
I fear a bit that some updates for sites might be more tricky, given that they deploy quite late. In this case it could happen that an update and an uninstall falls into the same import. Maybe though this restriction is fine.
What about adding this into a protected method and give it a good name?
We haven't tested schema mismatch nor version mismatch on themes.
At least the module handler is injected already into this class.
Can installation profiles have version numbers as well? Oh wait, they are included in the module list, right?
We should apply the updates to
\Drupal\KernelTests\KernelTestBase::enableModules
as well.Comment #33
xjm@alexpott, @catch, and I agreed that this is a major bug because of the impact for data integrity.
Comment #34
xjmWe might want to consider whether there is a risk of disruption here for some workflows (as @dawehner suggests). The patch requires (and has) an upgrade path, but I'm wondering if we should consider targeting this change for 8.2.x. On the other hand, though, the longer this is not fixed, the more likely it is that sites will get into a bad state with an invalid import, so maybe the risk of this not being fixed is greater. I can see the case for either. If we do target this for 8.1.x I think it definitely merits a CR and release notes mention, even though it is not actually an API change per se, because it could impact production workflows in unexpected ways.
Comment #35
pounardJust asking myself, would this mean that I can't arbitrary import configuration from a site instance to another where even a single one of my module's versions is not the same ? For example, reverting a most recent, in-development instance configuration using the production/stable environment configuration ? Or, let's say I just upgraded a single module but want to run my import once again ? Or I changed some version in my composer.json and run the site install with the upgraded module ?
Comment #36
alexpott@pounard well it would make these situations more tricky - but reverting to previous config that ran against a different code base is inherently dangerous and exactly what we want to prevent.
Comment #37
alexpottOne thing we could consider is ignoring the patch version to make it looser.
Comment #38
pounardActually, I do think this is gonna be so hard to work with CMI that I probably just won't. I mean, you are never expected to synchronize your config by accident.
I would definitely prefer having a "prod" vs "dev" environment (such as Symfony does) and be that cautious only in "prod" environment, but allow the developer to do about everything unsafe he needs to a "dev" environment.
Moreover, in real life, it does happen that you want to do something unsafe on a prod environment as long as you have tested it and know it'll work.
This restriction is way too heavy, it implies that no one will ever have the flexibility of doing unsafe upgrades; as soon as there is no work-around given with this, it gets critical for thousands of developers or dev-ops preventing them doing their upgrades or fixing broken environments with last resort measures.
I'm OK with this happening in D8, but only if I can write --no-strict or --no-check-versions option when running sync to be able to run unsafe upgrades. Users are not that stupid, let them do stupid things when they need to.
Comment #39
alexpott@pounard but wouldn't ignoring patch differences work + a flag to make dev's lives simple whilst protecting everyone from breaking their sites because the problem with
Is that if a site crashes to a white screen it is not so much letting them - it's trying to prevent irrecoverable mistakes.
Comment #40
jonathanshawIs ignoring patch version safe? That relies on module maintainers tagging versions perfectly. I'd rather be ultra safe, especially if problems don't necessarily show up immediately.
If there was a no-strict option that thrill seekers could use, it would make it difficult for anyone to object to being safe by default.
Comment #41
alexpottCreated #2762235: Ensure that ConfigImport is taking place without outstanding updates to do something smaller and easier to agree on.
Comment #44
fagoThat was my immediate thought as well - that would make config imports a quite useless tool for every day project deployments. It seems to me that what we lack here is config schema versioning. We can only decide whether some config is safe to import based upon config schema versions. Best that would follow something like semantic versioning also, so that additions can be done in patch level changes and upgrades in minor level changes. Major version changes in config schema shouldn'T occour, that would be a major version change in the whole module imo.
Comment #45
bircherI agree with fago here. At the very least we need to have an option to use the
--force
.I guess one of the points is make sure everybody uses a safe sequence when updating and deploying configuration of a site. And as such the updates have to run ALWAYS first as the point of update hooks is to make sure the database schema is back in sync with the code current version. (And the post_update hooks to fix the content broken in the update hook.) And only then import configuration and then fixing the content broken due to configuration changes. And that is already on a good path with #2762235: Ensure that ConfigImport is taking place without outstanding updates.
We don't at the moment have an easy way to know whether the configuration change was made by a site builder or a schema change (and thus the module maintainer.) Or do we?
Comment #48
timmillwoodOn almost 2 years to the day, here's an attempt at re-rolling #27.
Comment #50
alexpottThe newer KernelTestBase has a slightly different way of installing the initial set of modules. Fixed in the patch attached. I also rerolled the patch from my own 2-yr old branch.
Comment #52
Manuel Garcia CreditAttribution: Manuel Garcia as a volunteer and at Appnovation for Pfizer, Inc. commentedReroll after a year.
Fixed conflicts manually on:
Comment #61
colanFrom #44:
The process for one of my current projects, when I found it, was to run `drush deploy` in the dev environment (after cloning DB & files from Prod), and then import config. If all went well, we'd do this on Prod. A little while ago, I noticed that upstream config was missing even though the DB schemas were up-to-date.
What I eventually discovered was that new config was generated, but was then being overwritten as discussed in #3285200-17: Importing older config without the mysql/pgsql module enabled will generate error. I then rewrote the process to match the new documentation.
The problem is that you don't get any errors, like in #3285200: Importing older config without the mysql/pgsql module enabled will generate error, but you eventually discover that you're missing config even though your DB schema is up-to-date. Would it be possible to prevent running `drush config:import` if it would be overwriting older config?
To do this, we'd certainly need to version each config file so that when you try to overwrite, the system can stop you from "overwriting the data with an out-of-date backup", but it could be more trouble than it's worth.
Comment #62
geek-merlinWhat about keeping it simple, and just take the randomness out of site management:
Nothing evil happens if
- after composer require/remove/update, you do db-update AND config-export (the schema might have changed)
If on config-export, we save a copy of composer.json&lock to the config-export, we can add suitable warnings:
- "The requested config-import does not match current codebase. Diff: ..."
One step further: Provide a composer plugin that triggers db-dump, db-update, config-export. This ensures non mismatch in the first place.
Comment #63
colanMakes sense to me so far. There are scenarios where you don't want/need to export config after an update though, say on Prod if you simply want to enforce your config there (which is usually the ultimate destination). To handle that, maybe we could support for:
drush updatedb --no-config-export
If you just run
drush updatedb
, you'd get a message like:The Composer plug-in is a little too gravy-ish for now. Let's worry about that one later. ;)
Comment #66
Wim LeersPer @catch, this could've prevented #3374544: TypeError: array_intersect(): Argument #1 ($array) must be of type array, string given in array_intersect() (line 203 of .../core/modules/ckeditor5/src/Plugin/CKEditor5PluginManager.php)..