9
9
10
10
import org .apache .logging .log4j .LogManager ;
11
11
import org .apache .logging .log4j .Logger ;
12
+ import org .elasticsearch .cluster .metadata .IndexMetadata ;
12
13
import org .elasticsearch .cluster .metadata .Metadata ;
14
+ import org .elasticsearch .common .UUIDs ;
13
15
import org .elasticsearch .common .compress .CompressedXContent ;
14
16
import org .elasticsearch .common .settings .Settings ;
17
+ import org .elasticsearch .core .CheckedFunction ;
15
18
import org .elasticsearch .index .IndexMode ;
16
19
import org .elasticsearch .index .IndexSettingProvider ;
17
20
import org .elasticsearch .index .IndexSettings ;
21
+ import org .elasticsearch .index .IndexVersion ;
22
+ import org .elasticsearch .index .mapper .MapperService ;
18
23
24
+ import java .io .IOException ;
25
+ import java .io .UncheckedIOException ;
19
26
import java .time .Instant ;
20
27
import java .util .List ;
21
- import java .util .Locale ;
28
+
29
+ import static org .elasticsearch .cluster .metadata .IndexMetadata .INDEX_ROUTING_PATH ;
22
30
23
31
/**
24
32
* An index setting provider that overwrites the source mode from synthetic to stored if synthetic source isn't allowed to be used.
25
33
*/
26
- public class SyntheticSourceIndexSettingsProvider implements IndexSettingProvider {
34
+ final class SyntheticSourceIndexSettingsProvider implements IndexSettingProvider {
27
35
28
36
private static final Logger LOGGER = LogManager .getLogger (SyntheticSourceIndexSettingsProvider .class );
29
37
30
38
private final SyntheticSourceLicenseService syntheticSourceLicenseService ;
39
+ private final CheckedFunction <IndexMetadata , MapperService , IOException > mapperServiceFactory ;
31
40
32
- public SyntheticSourceIndexSettingsProvider (SyntheticSourceLicenseService syntheticSourceLicenseService ) {
41
+ SyntheticSourceIndexSettingsProvider (
42
+ SyntheticSourceLicenseService syntheticSourceLicenseService ,
43
+ CheckedFunction <IndexMetadata , MapperService , IOException > mapperServiceFactory
44
+ ) {
33
45
this .syntheticSourceLicenseService = syntheticSourceLicenseService ;
46
+ this .mapperServiceFactory = mapperServiceFactory ;
34
47
}
35
48
36
49
@ Override
@@ -43,19 +56,68 @@ public Settings getAdditionalIndexSettings(
43
56
Settings indexTemplateAndCreateRequestSettings ,
44
57
List <CompressedXContent > combinedTemplateMappings
45
58
) {
46
- if (newIndexHasSyntheticSourceUsage (indexTemplateAndCreateRequestSettings )
59
+ if (newIndexHasSyntheticSourceUsage (indexName , isTimeSeries , indexTemplateAndCreateRequestSettings , combinedTemplateMappings )
47
60
&& syntheticSourceLicenseService .fallbackToStoredSource ()) {
48
61
LOGGER .debug ("creation of index [{}] with synthetic source without it being allowed" , indexName );
49
62
// TODO: handle falling back to stored source
50
63
}
51
64
return Settings .EMPTY ;
52
65
}
53
66
54
- boolean newIndexHasSyntheticSourceUsage (Settings indexTemplateAndCreateRequestSettings ) {
55
- // TODO: build tmp MapperService and check whether SourceFieldMapper#isSynthetic() to determine synthetic source usage.
56
- // Not using IndexSettings.MODE.get() to avoid validation that may fail at this point.
57
- var rawIndexMode = indexTemplateAndCreateRequestSettings .get (IndexSettings .MODE .getKey ());
58
- IndexMode indexMode = rawIndexMode != null ? Enum .valueOf (IndexMode .class , rawIndexMode .toUpperCase (Locale .ROOT )) : null ;
59
- return indexMode != null && indexMode .isSyntheticSourceEnabled ();
67
+ boolean newIndexHasSyntheticSourceUsage (
68
+ String indexName ,
69
+ boolean isTimeSeries ,
70
+ Settings indexTemplateAndCreateRequestSettings ,
71
+ List <CompressedXContent > combinedTemplateMappings
72
+ ) {
73
+ if ("validate-index-name" .equals (indexName )) {
74
+ // This index name is used when validating component and index templates, we should skip this check in that case.
75
+ // (See MetadataIndexTemplateService#validateIndexTemplateV2(...) method)
76
+ return false ;
77
+ }
78
+
79
+ var tmpIndexMetadata = buildIndexMetadataForMapperService (indexName , isTimeSeries , indexTemplateAndCreateRequestSettings );
80
+ try (var mapperService = mapperServiceFactory .apply (tmpIndexMetadata )) {
81
+ // combinedTemplateMappings can be null when creating system indices
82
+ // combinedTemplateMappings can be empty when creating a normal index that doesn't match any template and without mapping.
83
+ if (combinedTemplateMappings == null || combinedTemplateMappings .isEmpty ()) {
84
+ combinedTemplateMappings = List .of (new CompressedXContent ("{}" ));
85
+ }
86
+ mapperService .merge (MapperService .SINGLE_MAPPING_NAME , combinedTemplateMappings , MapperService .MergeReason .INDEX_TEMPLATE );
87
+ return mapperService .documentMapper ().sourceMapper ().isSynthetic ();
88
+ } catch (IOException e ) {
89
+ throw new UncheckedIOException (e );
90
+ }
91
+ }
92
+
93
+ // Create a dummy IndexMetadata instance that can be used to create a MapperService in order to check whether synthetic source is used:
94
+ private IndexMetadata buildIndexMetadataForMapperService (
95
+ String indexName ,
96
+ boolean isTimeSeries ,
97
+ Settings indexTemplateAndCreateRequestSettings
98
+ ) {
99
+ var tmpIndexMetadata = IndexMetadata .builder (indexName );
100
+
101
+ int dummyPartitionSize = IndexMetadata .INDEX_ROUTING_PARTITION_SIZE_SETTING .get (indexTemplateAndCreateRequestSettings );
102
+ int dummyShards = indexTemplateAndCreateRequestSettings .getAsInt (
103
+ IndexMetadata .SETTING_NUMBER_OF_SHARDS ,
104
+ dummyPartitionSize == 1 ? 1 : dummyPartitionSize + 1
105
+ );
106
+ int shardReplicas = indexTemplateAndCreateRequestSettings .getAsInt (IndexMetadata .SETTING_NUMBER_OF_REPLICAS , 0 );
107
+ var finalResolvedSettings = Settings .builder ()
108
+ .put (IndexMetadata .SETTING_VERSION_CREATED , IndexVersion .current ())
109
+ .put (indexTemplateAndCreateRequestSettings )
110
+ .put (IndexMetadata .SETTING_NUMBER_OF_SHARDS , dummyShards )
111
+ .put (IndexMetadata .SETTING_NUMBER_OF_REPLICAS , shardReplicas )
112
+ .put (IndexMetadata .SETTING_INDEX_UUID , UUIDs .randomBase64UUID ());
113
+
114
+ if (isTimeSeries ) {
115
+ finalResolvedSettings .put (IndexSettings .MODE .getKey (), IndexMode .TIME_SERIES );
116
+ // Avoid failing because index.routing_path is missing (in case fields are marked as dimension)
117
+ finalResolvedSettings .putList (INDEX_ROUTING_PATH .getKey (), List .of ("path" ));
118
+ }
119
+
120
+ tmpIndexMetadata .settings (finalResolvedSettings );
121
+ return tmpIndexMetadata .build ();
60
122
}
61
123
}
0 commit comments