Problem/Motivation
The recipe spec introduces persistent alters of config. A recipe can define a set of actions to apply to configuration that's provided either by an installed extension or by a recipe. Which is a great feature.
But should we be special-casing recipes here? Recipes don't support an upgrade path for the config they provide, including their config actions. Distribution authors may require an upgrade path for their config, including the config actions they ship with.
This is a demonstrated need we can see in existing distributions.
The two contrib modules that provide stand-alone support for extensions to provide config actions or alters are Configuration Rewrite and Config Actions. Looking at the list of modules that require Configuration Rewrite or require Config Actions, many use them in a distribution context.
For example, in the Opigno distribution, the Opigno Class module uses Configuration Rewrite to assign permissions to roles. The rewrite files have changed a number of times over the years with the changes applied as updates via the update system.
Similarly, the Drutopia distribution makes extensive use of config actions in its feature modules. An example is the Drutopia Site module, which provides config actions that apply permissions to several roles. Like those of Opigno Class, these config actions have received several changes over time. Through integration with Configuration Synchronizer via Config Actions Provider, Drutopia sites receive the new user role permission updates along with other config updates.
In any case, support for persistent config alters puts the issue #2960941: Provide an API for persistent configuration alters, including for extension-provided config into scope for the distribution modernization initiative.
In practice, adding support for extension-provided config actions would change the recipe .yml file format in two ways.
First, Recipe config actions are provided as files in for example config/actions/user.role.editor.yml rather than being defined directly in the recipe.
Second, actions listed in the recipe are provided by extensions and follow the same pattern as, for example, install config:
actions:
easy_breadcrumb:
- user.role.anonymous
Issue fork distributions_recipes-3284025
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
nedjoComment #3
nedjoSketching in details of how this would change the recipe format.
Comment #4
alexpottTweaking this issue to be part of the recipe roadmap.
I think all the text in the issue summary is a great background to how contrib has solved an extremely similar problem space. This issue will explore adding an API to supporting config actions to core and blocks work on #3292285: Add the ability to define configuration actions in recipes.
Comment #7
alexpottSorting out issue credit. Note this issue is nowhere near landing but just don't want to forget.
Comment #8
nedjoComing from #3283900-7: Define recipe runtime configuration update requirements where we're discussing what happens when a recipe is reapplied, there are related issues here. It looks like actions are going to present some very basic problems for the current recipe spec.
Currently, when applying a recipe, we raise an exception if a config item exists on the site and is different from the provided version. But to answer that question - "is this configuration in its provided state?", or put differently "has a site admin customized/overridden this config item?" - we have to know about all the actions that have been applied--not only by the current recipe but by all previously-applied ones.
Which we can't determine, since recipes are ephemeral and leave no record even of having been applied.
As a sample use case, we expect a low level recipe to provide a user role like a "content editor" (as core's standard profile currently does) and many other recipes to apply actions to that user role in order to add permissions. The current recipe code, which tests a config item as provided against the version in the active storage, will raise an exception if any such actions have been applied. But those applied actions don't mean the item has been admin-customized.
A second area of challenge is support for "reverting". A common requirement on distribution-based sites is the option to selectively "revert" to configuration as provided. If only extension-provided config actions are applied on reversion, any actions originally from a recipe will be lost, which in many or most cases will not be what's desired or expected.
In the Configuration Synchronizer module set, we determine applicable actions via the Config Actions Provider helper module. We can't use that same approach though with recipes as currently structured, because once applied they are not available to answer questions such as what alters have been provided.
Part of a solution likely will be snapshotting config as provided and altered through config actions, since only through snapshotting can we answer questions about a prior state no longer available. The relevant core issue is #2960870: Snapshot configuration as installed and updated from recipes and extensions.
Personally though, I think a fuller solution would include #3284159: Decouple config provision from recipe, so we don't need different handling for recipe-provided vs. extension-provided config.
Comment #9
alexpott@nedjo thanks for the thoughtful comment in #8.
Wrt to the user role and adding permissions example... the code here will allow recipes to call the grant permissions config action and as longs the permission can be successful granted this will work - it does not care if the role already as the permission. I think what you are alluding to here is that if a recipe provides configuration and the site has the configuration already and that does not match then currently the recipe code throws an exception. I think we can explore in the future having a force option on the recipe apply command. This option also will work for the revert case. Obviously this might end up reverting something you don't want to but that's always the case and (for me) the reason why the revert use-case is never as useful as you'd think.
I agree that we should improve snapshotting so that user has more control and it's easier to get back to known states. I think snapshotting might be the best path to offering an undo is something goes wrong when applying a recipe for example.
With above said I think that the comment in #8 does not directly apply to the code in the MR. The MR is a new api for core that will be leveraged by recipes but is completely agnostic of recipes.
Comment #10
alexpottReading the discussion online about trying to using recipes already I think we need this functionality there so we can meet some of the expectations. Therefore, I think will merge this as is. That should not stop further discussion about this API. It would be great if people open further issues focussing on config action api code review and missing features. For example I think we should extend the method attribute to determine if the method is static and call it appropriately. We could also somehow indicate that an array values should be turned into separate method calls (for example to allow multiple permissions to be granted in a single action).
Comment #11
alexpottComment #13
alexpottI've merged this in order to start experimenting with config actions and recipes. However, as with all over merges to the initiative repository - nothing is set in stone - all classes and marked as @internal and final and we're making no promises. I.e. we're free to rip this up and re-implement.