|
| 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