Skip to content

Commit 50861c1

Browse files
authored
Add package docs for reserved state (elastic#120790)
Add 8.x versions of reserved state docs
1 parent 8769513 commit 50861c1

File tree

1 file changed

+136
-0
lines changed

1 file changed

+136
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
/**
11+
* This package is responsible for managing reserved cluster state and handlers.
12+
* <p>
13+
* The purpose of reserved state is to update and persist various changes to cluster state,
14+
* generated from an information source (eg a file), and ensure that those changes
15+
* cannot then be overridden by anything other than that which owns those changes.
16+
* <p>
17+
* The cluster state changes themselves can be any modification to cluster state,
18+
* and classes performing those changes are pluggable.
19+
* <p>
20+
* There are several main classes in this package and sub-packages:
21+
* <ul>
22+
* <li>
23+
* {@link org.elasticsearch.reservedstate.service.FileSettingsService} reads information from a settings file, deserializes it,
24+
* and passes it to {@code ReservedClusterStateService} to process
25+
* </li>
26+
* <li>
27+
* {@link org.elasticsearch.reservedstate.service.ReservedClusterStateService} takes deserialized information
28+
* from {@code FileSettingsService} and calls various registered handlers to update cluster state with the information.
29+
* </li>
30+
* <li>
31+
* Implementations of {@link org.elasticsearch.reservedstate.ReservedClusterStateHandler} take specific parts
32+
* of the deserialized information and updates cluster state accordingly.
33+
* </li>
34+
* <li>
35+
* {@link org.elasticsearch.cluster.metadata.ReservedStateMetadata} contains information on reserved state applicability,
36+
* and is used to filter and prevent changes to cluster state that would override reserved state.
37+
* </li>
38+
* <li>
39+
* {@link org.elasticsearch.reservedstate.ActionWithReservedState} helps REST handlers to detect operations that would
40+
* override reserved state updates, and deny the request.
41+
* </li>
42+
* </ul>
43+
* <h2>Operation overview</h2>
44+
* There are several steps to managing reserved state. The basic sequence of operations is:
45+
* <ol>
46+
* <li>
47+
* One or more changes to settings files are made. This is detected by {@code FileSettingsService}, the changes are deserialized,
48+
* and the deserialized XContent is passed to {@code ReservedClusterStateService}.
49+
* </li>
50+
* <li>
51+
* {@code ReservedClusterStateService} checks the overall metadata of the update to determine if it needs to be applied at all.
52+
* If it does, it determines which {@code ReservedClusterStateHandler} implementations need to be called, based on which
53+
* keys exist in the update state, and passes them the relevant information to generate a new cluster state
54+
* (first doing a trial run to see if the update is actually valid).
55+
* </li>
56+
* <li>
57+
* Metadata on the update is stored in cluster state for each handler,
58+
* alongside the arbitrary changes done to cluster state by the applicable handlers.
59+
* </li>
60+
* <li>
61+
* If there is a REST counterpart to a reserved state handler, the REST implementation calls
62+
* {@link org.elasticsearch.reservedstate.ActionWithReservedState#validateForReservedState} to determine if the REST call
63+
* will modify any information generated by the corresponding reserved state handler. If it does, the REST handler
64+
* denies the request.
65+
* </li>
66+
* </ol>
67+
*
68+
* Importantly, each update to cluster state by a call to {@code ReservedStateService.process} is done <em>atomically</em> -
69+
* either all updates from all registered and applicable handlers are applied, or none are.
70+
*
71+
* <h2>Reserved state metadata keys</h2>
72+
* An important concept to understand is that <em>reserved state is only reserved through the cooperation of REST handlers</em>
73+
* (or any other part of the system that could modify cluster state). A reserved state handler implementation can modify <em>any</em>
74+
* aspect of cluster state - it is not up to the reserved state service to monitor that. It is therefore the responsibility of
75+
* <em>all other aspects of the system</em> that could potentially modify that same state to cooperate with the handler implementation
76+
* to block conflicting updates before they happen.
77+
* <p>
78+
* To help with this, a handler returns a set of arbitrary string keys alongside the updated cluster state, and these keys are stored
79+
* in the reserved state metadata for that handler. No meaning is ascribed to those keys by the reserved state infrastructure,
80+
* but it is expected that they represent or tag the cluster state changes in some meaningful way to that handler.
81+
* Any REST handlers that could modify the same state needs to check if it is going to modify state corresponding
82+
* to reserved metadata keys. If the key corresponding to the change it is going to make is present in the reserved state metadata,
83+
* the request should be denied.
84+
* <p>
85+
* For example, if there is a reserved state handler to set index templates, a file setting could create index templates {@code IT_1}
86+
* and {@code IT_2}. As well as adding those templates to the set of templates already present in the cluster, the reserved state handler
87+
* will set {@code [IT_1, IT_2]} as its reserved state metadata keys.
88+
* <p>
89+
* Later, if there is a REST request to modify {@code IT_1} or {@code IT_2}, the REST handler should check those strings against
90+
* the reserved metadata keys for the index template handler. As those keys are reserved, all requests to modify them via REST
91+
* should be denied.
92+
*
93+
* <h2>Reserved state update details</h2>
94+
*
95+
* <h3>Reserved state namespace</h3>
96+
* Every reserved state handler has a <em>namespace</em> that it operates under. This is used to scope all handlers and metadata
97+
* stored in cluster state (although every namespace is checked for conflicts
98+
* by {@link org.elasticsearch.reservedstate.ActionWithReservedState}).
99+
* <p>
100+
* There is currently only one namespace defined by Elasticsearch itself, {@code file_settings}
101+
* defined by {@link org.elasticsearch.reservedstate.service.FileSettingsService#NAMESPACE}. Other namespaces may be defined
102+
* by plugins and modules.
103+
*
104+
* <h3>Reserved state version and compatibility</h3>
105+
* Every reserved state namespace also has a <em>version</em> associated with it. This is a simple integer,
106+
* that should be incremented whenever a new change should be applied (eg a new version of the settings file is written).
107+
* This is used to de-duplicate multiple calls to {@code process}, and to handle races that could occur between updates;
108+
* to determine if the changes should actually result in modifications to cluster state, or if the cluster state already has those changes
109+
* if the stored metadata version is greater than the version of the update.
110+
*
111+
* <h3>Handler ordering</h3>
112+
* There may be a dependency between the execution of multiple handlers, for example if one handler requires structures to exist
113+
* that are only created by another handler. This relationship can be represented by overriding the
114+
* {@link org.elasticsearch.reservedstate.ReservedClusterStateHandler#dependencies} and
115+
* {@link org.elasticsearch.reservedstate.ReservedClusterStateHandler#optionalDependencies} methods, to specify other handlers
116+
* that must be registered and be run before this one, and ones that should be run before this one
117+
* only if they are registered with the reserved state service.
118+
*
119+
* <h3>Trial runs and errors</h3>
120+
* If invalid data is given to a REST endpoint, the HTTP response can indicate the problem and that the request was denied.
121+
* No such response mechanism exists for information written to files. Furthermore, there is no opportunity to test changes;
122+
* if a settings file causes invalid updates to cluster state, or a handler to throw exceptions, then there is also no way
123+
* to roll back. To solve this, there is a space in the metadata for each reserved state namespace to store error information,
124+
* which can be seen in a dump of cluster state.
125+
* <p>
126+
* Before reserved state handlers update the 'real' cluster state, a trial run is performed on whatever the current cluster state
127+
* is at the time. If an exception is thrown at any point, or while deserializing update information, then the reserved state
128+
* update is not applied. Instead the error metadata for that namespace is set in cluster state, and the cluster state
129+
* is left as-is. If a subsequent update succeeds (ie the file data is corrected), then the error metadata is cleared.
130+
* <p>
131+
* There is always a small risk that the trial run will succeed, but applying the updates to the real cluster state fails,
132+
* due to cluster state changing in the meantime, or a transient error in a handler.
133+
* In that case, the error will be logged and reported just like any other asynchronous cluster update - but reserved state
134+
* error metadata won't be written.
135+
*/
136+
package org.elasticsearch.reservedstate;

0 commit comments

Comments
 (0)