1616import org .elasticsearch .common .Strings ;
1717import org .elasticsearch .common .io .stream .StreamInput ;
1818import org .elasticsearch .common .io .stream .StreamOutput ;
19+ import org .elasticsearch .core .Nullable ;
1920import org .elasticsearch .license .LicenseUtils ;
2021import org .elasticsearch .license .XPackLicenseState ;
2122import org .elasticsearch .xcontent .ConstructingObjectParser ;
3132import java .util .Objects ;
3233
3334import static org .elasticsearch .snapshots .SearchableSnapshotsSettings .SEARCHABLE_SNAPSHOTS_REPOSITORY_NAME_SETTING_KEY ;
35+ import static org .elasticsearch .snapshots .SearchableSnapshotsSettings .SEARCHABLE_SNAPSHOTS_SNAPSHOT_NAME_SETTING_KEY ;
3436import static org .elasticsearch .snapshots .SearchableSnapshotsSettings .SEARCHABLE_SNAPSHOT_PARTIAL_SETTING_KEY ;
3537import static org .elasticsearch .xpack .core .searchablesnapshots .SearchableSnapshotsConstants .SEARCHABLE_SNAPSHOT_FEATURE ;
3638
@@ -143,10 +145,12 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac
143145 IndexMetadata indexMetadata = clusterState .getMetadata ().index (index );
144146 assert indexMetadata != null : "index " + index .getName () + " must exist in the cluster state" ;
145147 String policyName = LifecycleSettings .LIFECYCLE_NAME_SETTING .get (indexMetadata .getSettings ());
146- if (indexMetadata .getSettings ().get (LifecycleSettings .SNAPSHOT_INDEX_NAME ) != null ) {
148+ SearchableSnapshotMetadata searchableSnapshotMetadata = extractSearchableSnapshotFromSettings (indexMetadata );
149+ if (searchableSnapshotMetadata != null ) {
150+ // TODO: allow this behavior instead of returning false, in this case the index is already a searchable a snapshot
151+ // so the most graceful way of recovery might be to use this repo
147152 // The index is already a searchable snapshot, let's see if the repository matches
148- String repo = indexMetadata .getSettings ().get (SEARCHABLE_SNAPSHOTS_REPOSITORY_NAME_SETTING_KEY );
149- if (this .snapshotRepository .equals (repo ) == false ) {
153+ if (this .snapshotRepository .equals (searchableSnapshotMetadata .repositoryName ) == false ) {
150154 // Okay, different repo, we need to go ahead with the searchable snapshot
151155 logger .debug (
152156 "[{}] action is configured for index [{}] in policy [{}] which is already mounted as a searchable "
@@ -155,15 +159,14 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac
155159 SearchableSnapshotAction .NAME ,
156160 index .getName (),
157161 policyName ,
158- repo ,
162+ searchableSnapshotMetadata . repositoryName ,
159163 this .snapshotRepository
160164 );
161165 return false ;
162166 }
163167
164168 // Check to the storage type to see if we need to convert between full <-> partial
165- final boolean partial = indexMetadata .getSettings ().getAsBoolean (SEARCHABLE_SNAPSHOT_PARTIAL_SETTING_KEY , false );
166- MountSearchableSnapshotRequest .Storage existingType = partial
169+ MountSearchableSnapshotRequest .Storage existingType = searchableSnapshotMetadata .partial
167170 ? MountSearchableSnapshotRequest .Storage .SHARED_CACHE
168171 : MountSearchableSnapshotRequest .Storage .FULL_COPY ;
169172 MountSearchableSnapshotRequest .Storage type = getConcreteStorageType (preActionBranchingKey );
@@ -174,7 +177,7 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac
174177 SearchableSnapshotAction .NAME ,
175178 index .getName (),
176179 policyName ,
177- repo ,
180+ searchableSnapshotMetadata . repositoryName ,
178181 type
179182 );
180183 return true ;
@@ -211,7 +214,7 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac
211214 // When generating a snapshot, we either jump to the force merge step, or we skip the
212215 // forcemerge and go straight to steps for creating the snapshot
213216 StepKey keyForSnapshotGeneration = forceMergeIndex ? forceMergeStepKey : generateSnapshotNameKey ;
214- // Branch, deciding whether there is an existing searchable snapshot snapshot that can be used for mounting the index
217+ // Branch, deciding whether there is an existing searchable snapshot that can be used for mounting the index
215218 // (in which case, skip generating a new name and the snapshot cleanup), or if we need to generate a new snapshot
216219 BranchingStep skipGeneratingSnapshotStep = new BranchingStep (
217220 skipGeneratingSnapshotKey ,
@@ -221,7 +224,8 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac
221224 IndexMetadata indexMetadata = clusterState .getMetadata ().index (index );
222225 String policyName = LifecycleSettings .LIFECYCLE_NAME_SETTING .get (indexMetadata .getSettings ());
223226 LifecycleExecutionState lifecycleExecutionState = LifecycleExecutionState .fromIndexMetadata (indexMetadata );
224- if (lifecycleExecutionState .getSnapshotName () == null ) {
227+ SearchableSnapshotMetadata searchableSnapshotMetadata = extractSearchableSnapshotFromSettings (indexMetadata );
228+ if (lifecycleExecutionState .getSnapshotName () == null && searchableSnapshotMetadata == null ) {
225229 // No name exists, so it must be generated
226230 logger .trace (
227231 "no snapshot name for index [{}] in policy [{}] exists, so one will be generated" ,
@@ -230,8 +234,20 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac
230234 );
231235 return false ;
232236 }
237+ String snapshotIndexName ;
238+ String snapshotName ;
239+ String repoName ;
240+ if (lifecycleExecutionState .getSnapshotName () != null ) {
241+ snapshotIndexName = lifecycleExecutionState .getSnapshotIndexName ();
242+ snapshotName = lifecycleExecutionState .getSnapshotName ();
243+ repoName = lifecycleExecutionState .getSnapshotRepository ();
244+ } else {
245+ snapshotIndexName = searchableSnapshotMetadata .sourceIndex ;
246+ snapshotName = searchableSnapshotMetadata .snapshotName ;
247+ repoName = searchableSnapshotMetadata .repositoryName ;
248+ }
233249
234- if (this .snapshotRepository .equals (lifecycleExecutionState . getSnapshotRepository () ) == false ) {
250+ if (this .snapshotRepository .equals (repoName ) == false ) {
235251 // A different repository is being used
236252 // TODO: allow this behavior instead of throwing an exception
237253 throw new IllegalArgumentException ("searchable snapshot indices may be converted only within the same repository" );
@@ -240,12 +256,14 @@ public List<Step> toSteps(Client client, String phase, StepKey nextStepKey, XPac
240256 // We can skip the generate, initial cleanup, and snapshot taking for this index, as we already have a generated snapshot.
241257 // This will jump ahead directly to the "mount snapshot" step
242258 logger .debug (
243- "an existing snapshot [{}] in repository [{}] (index name: [{}]) "
244- + "will be used for mounting [{}] as a searchable snapshot" ,
245- lifecycleExecutionState .getSnapshotName (),
246- lifecycleExecutionState .getSnapshotRepository (),
247- lifecycleExecutionState .getSnapshotIndexName (),
248- index .getName ()
259+ "Policy [{}] will use an existing snapshot [{}] in repository [{}] (index name: [{}]) "
260+ + "to mount [{}] as a searchable snapshot. This snapshot was found in the {}." ,
261+ policyName ,
262+ snapshotName ,
263+ snapshotRepository ,
264+ snapshotIndexName ,
265+ index .getName (),
266+ lifecycleExecutionState .getSnapshotName () != null ? "lifecycle execution state" : "metadata of " + index .getName ()
249267 );
250268 return true ;
251269 }
@@ -401,11 +419,53 @@ public boolean equals(Object o) {
401419 return false ;
402420 }
403421 SearchableSnapshotAction that = (SearchableSnapshotAction ) o ;
404- return Objects .equals (snapshotRepository , that .snapshotRepository );
422+ return Objects .equals (snapshotRepository , that .snapshotRepository ) && Objects . equals ( forceMergeIndex , that . forceMergeIndex ) ;
405423 }
406424
407425 @ Override
408426 public int hashCode () {
409- return Objects .hash (snapshotRepository );
427+ return Objects .hash (snapshotRepository , forceMergeIndex );
428+ }
429+
430+ @ Nullable
431+ static SearchableSnapshotMetadata extractSearchableSnapshotFromSettings (IndexMetadata indexMetadata ) {
432+ String indexName = indexMetadata .getSettings ().get (LifecycleSettings .SNAPSHOT_INDEX_NAME );
433+ if (indexName == null ) {
434+ return null ;
435+ }
436+ String snapshotName = indexMetadata .getSettings ().get (SEARCHABLE_SNAPSHOTS_SNAPSHOT_NAME_SETTING_KEY );
437+ String repo = indexMetadata .getSettings ().get (SEARCHABLE_SNAPSHOTS_REPOSITORY_NAME_SETTING_KEY );
438+ final boolean partial = indexMetadata .getSettings ().getAsBoolean (SEARCHABLE_SNAPSHOT_PARTIAL_SETTING_KEY , false );
439+ return new SearchableSnapshotMetadata (indexName , repo , snapshotName , partial );
410440 }
441+
442+ static class SearchableSnapshotMetadata {
443+ private final String sourceIndex ;
444+ private final String repositoryName ;
445+ private final String snapshotName ;
446+ private final boolean partial ;
447+
448+ SearchableSnapshotMetadata (String sourceIndex , String repositoryName , String snapshotName , boolean partial ) {
449+ this .sourceIndex = sourceIndex ;
450+ this .repositoryName = repositoryName ;
451+ this .snapshotName = snapshotName ;
452+ this .partial = partial ;
453+ }
454+
455+ public String sourceIndex () {
456+ return sourceIndex ;
457+ }
458+
459+ public String repositoryName () {
460+ return repositoryName ;
461+ }
462+
463+ public String snapshotName () {
464+ return snapshotName ;
465+ }
466+
467+ public boolean partial () {
468+ return partial ;
469+ }
470+ };
411471}
0 commit comments