-
Notifications
You must be signed in to change notification settings - Fork 8.5k
Description
Our current migration system assumes that the developer who created and registered a new saved object type is in charge of migrating any outdated state in that saved object. We haven't thought about the situation where a saved object contains state that was built by other, potentially unknown, developers. With many of our new features however, this will become an issue.
Consider:
URLs
The migration issue with URLs is heavily discussed in that above link, but I'll recap the situation here:
- Background search plugin registers BackgroundSearchCollection saved object which contains a reference to a URL. The application developer who owns that URL updates state. How does the Background search developer know about this and how do they migrate their saved objects?
- Threshold alerts build from embeddables - Threshold alert configuration is stored in a saved object, that will also contain a URL reference.
Embeddables & actions
I recently realized that once we have embeddables that are "by value" instead of by reference, we will hit the same situation. The developer of dashboard saved objects is in charge of migrating them, but this developer doesn't know how to migrate the panels inside it, because those are extensible and owned by other developers.
There is actually a third layer here as well... actions. Actions can be attached to certain embeddables and will also be stored together with the embeddable input inside the dashboard. How will the author of an action update the state referenced in embeddables, inside dashboards.
Canvas workpads as well - we want to be able to update embeddables, but how do we migrate state from inside canvas workpads.
For URLs, the thought was to have each implementation expose a migrate method that the author of the saved objects can call. For Embeddables, this is a tougher problem and there are more considerations:
- Performance concerns if we have to parse and reconstruct every dashboard and child emebeddable to check
isLegacy. - Containers store partial children state in
explicitInput, and pass other state into the child via its own state. If we reconstruct the embeddable child, we can't just store the new input state fromembeddable.migrate().input- how do we split the state apart again to store the correct portion inexplicitInput? What happens if one child renames its input state fromfiltersto something else? Either the container, and every other child, would need to rename its input state to match, or we don't migrate and that child will no longer receive the correct data. - The cascading affect of multiple extension points being stored in a single saved object means we not only have to migrate every embeddable, but every embeddable needs to migrate any outdated actions.
Expressions
The expression string is stored in saved objects (Lens, Canvas workpads), but each expression function is extensible. How can a single developer of an expression function update the args or output shape, or expected input context without potentially breaking all those saved objects which reference it?
Even if we came up with a migration plan, we can still hit the issue where if the output or input shape changed, the previous, or following expression function may fail because it didn't update.
Expression system has a "cast types" system which we might be able to use.
Search strategies
What happens if we want to migrate the state a search strategy accepts? What if we need to migrate an expression function to account for that? For instance, hypothetical, SQL search strategy no longer supports some given syntax but this syntax is saved in an essql expression string? We have to potentially migrate canvas workpads, lens objects, dashboards (with in place embeddables). We also don't know for sure where else a plugin developer may be storing outdated state.
Any extension point / registry item
Essentially this boils down to having a generic migration system for anything stored in a registry. We need a way for third party developers to add migrations for state, whether that state is stored as a saved object, in a saved object, or just dynamically in code (consider the case of an embeddable hard coded into an application - how do we warn the user of the deprecation period before we end support completely and they need to migrate by).
Also keep in mind, this can go the other way. Any registry item may want to migrate its state structure, but this can have cascading affects, both up the chain and down. What if a childEmbeddable wants to change it' explicitInput from { name } to { firstName; lastName }. Because childEmbeddable state is stored up the chain (in a container, and that container's state stored somewhere, like a dashboard saved object, or hard coded in the SIEM overview page), those objects need to update the state. On the other hand migrations might float downward, for instance if dashboard embeddable wants to change its input state to accept { filters } instead of { timeRange, filters, query }. All the children embeddable need to update to accept the new version or they will eventually be broken.
Another example - think about how much state needs to be migrated if we want to change our Filters shape. Many potential saved objects and also a lot of code. How do we keep all of these in sync so we can support older saved objects that contain references to older versions?
I don't have a good solution to offer yet, though I think this might end up being an extremely generic state migration system that Saved Object migrations could be built on top of. It would be on the fly - only the saved object migration system would touch the Kibana database.
How important is this to tackle now vs later?
Well, we lived without saved object migrations for many years. We also already have lived with this problem with the expression language for awhile. It is going to be a problem when we want to have a stable API for third party developers, but in the short term we can work around this by keeping all teams in sync (e.g. we want to change the shape of Filters, we know all our saved objects and run time places that we need to migrate: expressions, actions, embeddables, etc).
I propose we focus on this in 8.x and I think the platform team should be involved, even if app arch ends up owning this, because of the overlap with saved object migrations.
I think we can continue to move forward with a direct access link service without being blocked on this, and I think we could probably continue to move forward with in place embeddables on a dashboard, even though knowing we may need to make some drastic migrations in order to support a new more robust system. This is by no means a small project though so I doubt there will be any 7.x resources for it.



