Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/128273.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 128273
summary: Improve get-snapshots message for unreadable repository
area: Snapshot/Restore
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
import org.elasticsearch.core.Predicates;
import org.elasticsearch.repositories.RepositoriesService;
import org.elasticsearch.repositories.RepositoryData;
import org.elasticsearch.repositories.RepositoryException;
import org.elasticsearch.repositories.RepositoryMissingException;
import org.elasticsearch.repositories.blobstore.BlobStoreRepository;
import org.elasticsearch.repositories.fs.FsRepository;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.test.ESTestCase;
Expand Down Expand Up @@ -633,6 +635,50 @@ public void testRetrievingSnapshotsWhenRepositoryIsMissing() throws Exception {
expectThrows(RepositoryMissingException.class, multiRepoFuture::actionGet);
}

public void testRetrievingSnapshotsWhenRepositoryIsUnreadable() throws Exception {
final String repoName = randomIdentifier();
final Path repoPath = randomRepoPath();
createRepository(
repoName,
"fs",
Settings.builder().put("location", repoPath).put(BlobStoreRepository.CACHE_REPOSITORY_DATA.getKey(), false)
);
createNSnapshots(repoName, randomIntBetween(1, 3));

try {
try (var directoryStream = Files.newDirectoryStream(repoPath)) {
for (final var directoryEntry : directoryStream) {
if (Files.isRegularFile(directoryEntry) && directoryEntry.getFileName().toString().startsWith("index-")) {
Files.writeString(directoryEntry, "invalid");
}
}
}

final var repositoryException = asInstanceOf(
RepositoryException.class,
safeAwaitFailure(
GetSnapshotsResponse.class,
l -> clusterAdmin().prepareGetSnapshots(TEST_REQUEST_TIMEOUT, repoName)
.setSort(SnapshotSortKey.NAME)
.setIgnoreUnavailable(randomBoolean())
.execute(l)
)
);
assertEquals(
Strings.format("[%s] cannot retrieve snapshots list from this repository", repoName),
repositoryException.getMessage()
);
assertEquals(
Strings.format("[%s] Unexpected exception when loading repository data", repoName),
repositoryException.getCause().getMessage()
);
} finally {
safeAwait(
l -> clusterAdmin().prepareDeleteRepository(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, repoName).execute(l.map(v -> null))
);
}
}

// Create a snapshot that is guaranteed to have a unique start time and duration for tests around ordering by either.
// Don't use this with more than 3 snapshots on platforms with low-resolution clocks as the durations could always collide there
// causing an infinite loop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.elasticsearch.repositories.RepositoriesService;
import org.elasticsearch.repositories.Repository;
import org.elasticsearch.repositories.RepositoryData;
import org.elasticsearch.repositories.RepositoryException;
import org.elasticsearch.repositories.RepositoryMissingException;
import org.elasticsearch.repositories.ResolvedRepositories;
import org.elasticsearch.search.sort.SortOrder;
Expand Down Expand Up @@ -285,7 +286,20 @@ private void populateResults(ActionListener<Void> listener) {
),
repositoryName -> asyncRepositoryContentsListener -> SubscribableListener

.<RepositoryData>newForked(l -> maybeGetRepositoryData(repositoryName, l))
.<RepositoryData>newForked(
l -> maybeGetRepositoryData(
repositoryName,
l.delegateResponse(
(ll, e) -> ll.onFailure(
new RepositoryException(
repositoryName,
"cannot retrieve snapshots list from this repository",
e
)
)
)
)
)
.andThenApply(repositoryData -> {
assert ThreadPool.assertCurrentThreadPool(ThreadPool.Names.MANAGEMENT);
cancellableTask.ensureNotCancelled();
Expand Down
Loading