Skip to content

Commit 4507821

Browse files
authored
Improve get-snapshots message for unreadable repository (#128273) (#128662)
Today if the get-snapshots API cannot access one of the repositories we return a fairly low-level message about the problem, perhaps something like `Could not determine repository generation from root blobs`. This message is shown verbatim in the Kibana UI so users need something a little more descriptive. With this commit we wrap the exception in one that indicates the problem in terms that users are more likely to understand. Relates #128208
1 parent 0ed7dff commit 4507821

File tree

3 files changed

+64
-1
lines changed

3 files changed

+64
-1
lines changed

docs/changelog/128273.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 128273
2+
summary: Improve get-snapshots message for unreadable repository
3+
area: Snapshot/Restore
4+
type: enhancement
5+
issues: []

server/src/internalClusterTest/java/org/elasticsearch/snapshots/GetSnapshotsIT.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
import org.elasticsearch.core.Predicates;
4141
import org.elasticsearch.repositories.RepositoriesService;
4242
import org.elasticsearch.repositories.RepositoryData;
43+
import org.elasticsearch.repositories.RepositoryException;
4344
import org.elasticsearch.repositories.RepositoryMissingException;
45+
import org.elasticsearch.repositories.blobstore.BlobStoreRepository;
4446
import org.elasticsearch.repositories.fs.FsRepository;
4547
import org.elasticsearch.search.sort.SortOrder;
4648
import org.elasticsearch.test.ESTestCase;
@@ -633,6 +635,48 @@ public void testRetrievingSnapshotsWhenRepositoryIsMissing() throws Exception {
633635
expectThrows(RepositoryMissingException.class, multiRepoFuture::actionGet);
634636
}
635637

638+
public void testRetrievingSnapshotsWhenRepositoryIsUnreadable() throws Exception {
639+
final String repoName = randomIdentifier();
640+
final Path repoPath = randomRepoPath();
641+
createRepository(
642+
repoName,
643+
"fs",
644+
Settings.builder().put("location", repoPath).put(BlobStoreRepository.CACHE_REPOSITORY_DATA.getKey(), false)
645+
);
646+
createNSnapshots(repoName, randomIntBetween(1, 3));
647+
648+
try {
649+
try (var directoryStream = Files.newDirectoryStream(repoPath)) {
650+
for (final var directoryEntry : directoryStream) {
651+
if (Files.isRegularFile(directoryEntry) && directoryEntry.getFileName().toString().startsWith("index-")) {
652+
Files.writeString(directoryEntry, "invalid");
653+
}
654+
}
655+
}
656+
657+
final var repositoryException = safeAwaitAndUnwrapFailure(
658+
RepositoryException.class,
659+
GetSnapshotsResponse.class,
660+
l -> clusterAdmin().prepareGetSnapshots(TEST_REQUEST_TIMEOUT, repoName)
661+
.setSort(SnapshotSortKey.NAME)
662+
.setIgnoreUnavailable(randomBoolean())
663+
.execute(l)
664+
);
665+
assertEquals(
666+
Strings.format("[%s] cannot retrieve snapshots list from this repository", repoName),
667+
repositoryException.getMessage()
668+
);
669+
assertEquals(
670+
Strings.format("[%s] Unexpected exception when loading repository data", repoName),
671+
repositoryException.getCause().getMessage()
672+
);
673+
} finally {
674+
safeAwait(
675+
l -> clusterAdmin().prepareDeleteRepository(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, repoName).execute(l.map(v -> null))
676+
);
677+
}
678+
}
679+
636680
// Create a snapshot that is guaranteed to have a unique start time and duration for tests around ordering by either.
637681
// Don't use this with more than 3 snapshots on platforms with low-resolution clocks as the durations could always collide there
638682
// causing an infinite loop

server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/get/TransportGetSnapshotsAction.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.elasticsearch.repositories.RepositoriesService;
3939
import org.elasticsearch.repositories.Repository;
4040
import org.elasticsearch.repositories.RepositoryData;
41+
import org.elasticsearch.repositories.RepositoryException;
4142
import org.elasticsearch.repositories.RepositoryMissingException;
4243
import org.elasticsearch.repositories.ResolvedRepositories;
4344
import org.elasticsearch.search.sort.SortOrder;
@@ -285,7 +286,20 @@ private void populateResults(ActionListener<Void> listener) {
285286
),
286287
repositoryName -> asyncRepositoryContentsListener -> SubscribableListener
287288

288-
.<RepositoryData>newForked(l -> maybeGetRepositoryData(repositoryName, l))
289+
.<RepositoryData>newForked(
290+
l -> maybeGetRepositoryData(
291+
repositoryName,
292+
l.delegateResponse(
293+
(ll, e) -> ll.onFailure(
294+
new RepositoryException(
295+
repositoryName,
296+
"cannot retrieve snapshots list from this repository",
297+
e
298+
)
299+
)
300+
)
301+
)
302+
)
289303
.andThenApply(repositoryData -> {
290304
assert ThreadPool.assertCurrentThreadPool(ThreadPool.Names.MANAGEMENT);
291305
cancellableTask.ensureNotCancelled();

0 commit comments

Comments
 (0)