Improve Clean Repository error message. (#117947)

This commit is contained in:
CJ Cenizal 2021-11-09 08:00:39 -08:00 committed by GitHub
parent 90395c5589
commit 69c0e6c601
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 83 additions and 294 deletions

View file

@ -22,7 +22,7 @@ const testBedConfig: TestBedConfig = {
const initTestBed = registerTestBed(WithAppDependencies(SnapshotRestoreHome), testBedConfig);
export interface HomeTestBed extends TestBed<HomeTestSubjects> {
export interface HomeTestBed extends TestBed {
actions: {
clickReloadButton: () => void;
selectRepositoryAt: (index: number) => void;
@ -115,271 +115,3 @@ export const setup = async (): Promise<HomeTestBed> => {
},
};
};
type HomeTestSubjects = TestSubjects | ThreeLevelDepth | NonVisibleTestSubjects;
type NonVisibleTestSubjects =
| 'snapshotDetail.sectionLoading'
| 'sectionLoading'
| 'emptyPrompt'
| 'emptyPrompt.documentationLink'
| 'emptyPrompt.title'
| 'emptyPrompt.registerRepositoryButton'
| 'repositoryDetail.sectionLoading'
| 'snapshotDetail.indexFailure';
type ThreeLevelDepth =
| 'snapshotDetail.uuid.value'
| 'snapshotDetail.state.value'
| 'snapshotDetail.version.value'
| 'snapshotDetail.includeGlobalState.value'
| 'snapshotDetail.indices.title'
| 'snapshotDetail.startTime.value'
| 'snapshotDetail.endTime.value'
| 'snapshotDetail.indexFailure.index'
| 'snapshotDetail.indices.value';
export type TestSubjects =
| 'appTitle'
| 'cell'
| 'cell.repositoryLink'
| 'cell.snapshotLink'
| 'checkboxSelectAll'
| 'checkboxSelectRow-my-repo'
| 'closeButton'
| 'content'
| 'content.documentationLink'
| 'content.duration'
| 'content.endTime'
| 'content.includeGlobalState'
| 'content.indices'
| 'content.repositoryType'
| 'content.snapshotCount'
| 'content.startTime'
| 'content.state'
| 'content.title'
| 'content.uuid'
| 'content.value'
| 'content.verifyRepositoryButton'
| 'content.version'
| 'deleteRepositoryButton'
| 'detailTitle'
| 'documentationLink'
| 'duration'
| 'duration.title'
| 'duration.value'
| 'editRepositoryButton'
| 'endTime'
| 'endTime.title'
| 'endTime.value'
| 'euiFlyoutCloseButton'
| 'includeGlobalState'
| 'includeGlobalState.title'
| 'includeGlobalState.value'
| 'indices'
| 'indices.title'
| 'indices.value'
| 'registerRepositoryButton'
| 'reloadButton'
| 'repositoryDetail'
| 'repositoryDetail.content'
| 'repositoryDetail.documentationLink'
| 'repositoryDetail.euiFlyoutCloseButton'
| 'repositoryDetail.repositoryType'
| 'repositoryDetail.snapshotCount'
| 'repositoryDetail.srRepositoryDetailsDeleteActionButton'
| 'repositoryDetail.srRepositoryDetailsFlyoutCloseButton'
| 'repositoryDetail.title'
| 'repositoryDetail.verifyRepositoryButton'
| 'repositoryLink'
| 'repositoryList'
| 'repositoryList.cell'
| 'repositoryList.checkboxSelectAll'
| 'repositoryList.checkboxSelectRow-my-repo'
| 'repositoryList.content'
| 'repositoryList.deleteRepositoryButton'
| 'repositoryList.documentationLink'
| 'repositoryList.editRepositoryButton'
| 'repositoryList.euiFlyoutCloseButton'
| 'repositoryList.registerRepositoryButton'
| 'repositoryList.reloadButton'
| 'repositoryList.repositoryDetail'
| 'repositoryList.repositoryLink'
| 'repositoryList.repositoryTable'
| 'repositoryList.repositoryType'
| 'repositoryList.row'
| 'repositoryList.snapshotCount'
| 'repositoryList.srRepositoryDetailsDeleteActionButton'
| 'repositoryList.srRepositoryDetailsFlyoutCloseButton'
| 'repositoryList.tableHeaderCell_name_0'
| 'repositoryList.tableHeaderCell_type_1'
| 'repositoryList.tableHeaderSortButton'
| 'repositoryList.title'
| 'repositoryList.verifyRepositoryButton'
| 'repositoryTable'
| 'repositoryTable.cell'
| 'repositoryTable.checkboxSelectAll'
| 'repositoryTable.checkboxSelectRow-my-repo'
| 'repositoryTable.deleteRepositoryButton'
| 'repositoryTable.editRepositoryButton'
| 'repositoryTable.repositoryLink'
| 'repositoryTable.row'
| 'repositoryTable.tableHeaderCell_name_0'
| 'repositoryTable.tableHeaderCell_type_1'
| 'repositoryTable.tableHeaderSortButton'
| 'repositoryType'
| 'row'
| 'row.cell'
| 'row.checkboxSelectRow-my-repo'
| 'row.deleteRepositoryButton'
| 'row.editRepositoryButton'
| 'row.repositoryLink'
| 'row.snapshotLink'
| 'snapshotCount'
| 'snapshotDetail'
| 'snapshotDetail.closeButton'
| 'snapshotDetail.content'
| 'snapshotDetail.detailTitle'
| 'snapshotDetail.duration'
| 'snapshotDetail.endTime'
| 'snapshotDetail.euiFlyoutCloseButton'
| 'snapshotDetail.includeGlobalState'
| 'snapshotDetail.indices'
| 'snapshotDetail.repositoryLink'
| 'snapshotDetail.startTime'
| 'snapshotDetail.state'
| 'snapshotDetail.tab'
| 'snapshotDetail.title'
| 'snapshotDetail.uuid'
| 'snapshotDetail.value'
| 'snapshotDetail.version'
| 'snapshotLink'
| 'snapshotList'
| 'snapshotListEmpty'
| 'snapshotList.cell'
| 'snapshotList.closeButton'
| 'snapshotList.content'
| 'snapshotList.detailTitle'
| 'snapshotList.duration'
| 'snapshotList.endTime'
| 'snapshotList.euiFlyoutCloseButton'
| 'snapshotList.includeGlobalState'
| 'snapshotList.indices'
| 'snapshotList.reloadButton'
| 'snapshotList.repositoryLink'
| 'snapshotList.row'
| 'snapshotList.snapshotDetail'
| 'snapshotList.snapshotLink'
| 'snapshotList.snapshotTable'
| 'snapshotList.startTime'
| 'snapshotList.state'
| 'snapshotList.tab'
| 'snapshotList.tableHeaderCell_durationInMillis_3'
| 'snapshotList.tableHeaderCell_indices_4'
| 'snapshotList.tableHeaderCell_repository_1'
| 'snapshotList.tableHeaderCell_snapshot_0'
| 'snapshotList.tableHeaderCell_startTimeInMillis_2'
| 'snapshotList.tableHeaderSortButton'
| 'snapshotList.title'
| 'snapshotList.uuid'
| 'snapshotList.value'
| 'snapshotList.version'
| 'snapshotRestoreApp'
| 'snapshotRestoreApp.appTitle'
| 'snapshotRestoreApp.cell'
| 'snapshotRestoreApp.checkboxSelectAll'
| 'snapshotRestoreApp.checkboxSelectRow-my-repo'
| 'snapshotRestoreApp.closeButton'
| 'snapshotRestoreApp.content'
| 'snapshotRestoreApp.deleteRepositoryButton'
| 'snapshotRestoreApp.detailTitle'
| 'snapshotRestoreApp.documentationLink'
| 'snapshotRestoreApp.duration'
| 'snapshotRestoreApp.editRepositoryButton'
| 'snapshotRestoreApp.endTime'
| 'snapshotRestoreApp.euiFlyoutCloseButton'
| 'snapshotRestoreApp.includeGlobalState'
| 'snapshotRestoreApp.indices'
| 'snapshotRestoreApp.registerRepositoryButton'
| 'snapshotRestoreApp.reloadButton'
| 'snapshotRestoreApp.repositoryDetail'
| 'snapshotRestoreApp.repositoryLink'
| 'snapshotRestoreApp.repositoryList'
| 'snapshotRestoreApp.repositoryTable'
| 'snapshotRestoreApp.repositoryType'
| 'snapshotRestoreApp.row'
| 'snapshotRestoreApp.snapshotCount'
| 'snapshotRestoreApp.snapshotDetail'
| 'snapshotRestoreApp.snapshotLink'
| 'snapshotRestoreApp.snapshotList'
| 'snapshotRestoreApp.snapshotTable'
| 'snapshotRestoreApp.srRepositoryDetailsDeleteActionButton'
| 'snapshotRestoreApp.srRepositoryDetailsFlyoutCloseButton'
| 'snapshotRestoreApp.startTime'
| 'snapshotRestoreApp.state'
| 'snapshotRestoreApp.tab'
| 'snapshotRestoreApp.tableHeaderCell_durationInMillis_3'
| 'snapshotRestoreApp.tableHeaderCell_indices_4'
| 'snapshotRestoreApp.tableHeaderCell_name_0'
| 'snapshotRestoreApp.tableHeaderCell_repository_1'
| 'snapshotRestoreApp.tableHeaderCell_snapshot_0'
| 'snapshotRestoreApp.tableHeaderCell_startTimeInMillis_2'
| 'snapshotRestoreApp.tableHeaderCell_type_1'
| 'snapshotRestoreApp.tableHeaderSortButton'
| 'snapshotRestoreApp.title'
| 'snapshotRestoreApp.uuid'
| 'snapshotRestoreApp.value'
| 'snapshotRestoreApp.verifyRepositoryButton'
| 'snapshotRestoreApp.version'
| 'snapshotTable'
| 'snapshotTable.cell'
| 'snapshotTable.repositoryLink'
| 'snapshotTable.row'
| 'snapshotTable.snapshotLink'
| 'snapshotTable.tableHeaderCell_durationInMillis_3'
| 'snapshotTable.tableHeaderCell_indices_4'
| 'snapshotTable.tableHeaderCell_repository_1'
| 'snapshotTable.tableHeaderCell_snapshot_0'
| 'snapshotTable.tableHeaderCell_startTimeInMillis_2'
| 'snapshotTable.tableHeaderSortButton'
| 'srRepositoryDetailsDeleteActionButton'
| 'srRepositoryDetailsFlyoutCloseButton'
| 'startTime'
| 'startTime.title'
| 'startTime.value'
| 'state'
| 'state.title'
| 'state.value'
| 'repositories_tab'
| 'snapshots_tab'
| 'policies_tab'
| 'restore_status_tab'
| 'tableHeaderCell_durationInMillis_3'
| 'tableHeaderCell_durationInMillis_3.tableHeaderSortButton'
| 'tableHeaderCell_indices_4'
| 'tableHeaderCell_indices_4.tableHeaderSortButton'
| 'tableHeaderCell_name_0'
| 'tableHeaderCell_name_0.tableHeaderSortButton'
| 'tableHeaderCell_repository_1'
| 'tableHeaderCell_repository_1.tableHeaderSortButton'
| 'tableHeaderCell_shards.failed_6'
| 'tableHeaderCell_shards.total_5'
| 'tableHeaderCell_snapshot_0'
| 'tableHeaderCell_snapshot_0.tableHeaderSortButton'
| 'tableHeaderCell_startTimeInMillis_2'
| 'tableHeaderCell_startTimeInMillis_2.tableHeaderSortButton'
| 'tableHeaderCell_type_1'
| 'tableHeaderCell_type_1.tableHeaderSortButton'
| 'tableHeaderSortButton'
| 'title'
| 'uuid'
| 'uuid.title'
| 'uuid.value'
| 'value'
| 'verifyRepositoryButton'
| 'version'
| 'version.title'
| 'version.value'
| 'maxSnapshotsWarning'
| 'repositoryErrorsWarning'
| 'repositoryErrorsPrompt';

View file

@ -92,11 +92,12 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => {
const setCleanupRepositoryResponse = (response?: HttpResponse, error?: any) => {
const status = error ? error.status || 503 : 200;
const body = error ? JSON.stringify(error) : JSON.stringify(response);
server.respondWith('POST', `${API_BASE_PATH}repositories/:name/cleanup`, [
status,
{ 'Content-Type': 'application/json' },
JSON.stringify(response),
body,
]);
};

View file

@ -372,6 +372,60 @@ describe('<SnapshotRestoreHome />', () => {
expect(latestRequest.method).toBe('GET');
expect(latestRequest.url).toBe(`${API_BASE_PATH}repositories/${repo1.name}/verify`);
});
describe('clean repository', () => {
test('shows results when request succeeds', async () => {
httpRequestsMockHelpers.setCleanupRepositoryResponse({
cleanup: {
cleaned: true,
response: {
results: {
deleted_bytes: 0,
deleted_blobs: 0,
},
},
},
});
const { exists, find, component } = testBed;
await act(async () => {
find('repositoryDetail.cleanupRepositoryButton').simulate('click');
});
component.update();
const latestRequest = server.requests[server.requests.length - 1];
expect(latestRequest.method).toBe('POST');
expect(latestRequest.url).toBe(`${API_BASE_PATH}repositories/${repo1.name}/cleanup`);
expect(exists('repositoryDetail.cleanupCodeBlock')).toBe(true);
expect(exists('repositoryDetail.cleanupError')).toBe(false);
});
test('shows error when success fails', async () => {
httpRequestsMockHelpers.setCleanupRepositoryResponse({
cleanup: {
cleaned: false,
error: {
message: 'Error message',
statusCode: 400,
},
},
});
const { exists, find, component } = testBed;
await act(async () => {
find('repositoryDetail.cleanupRepositoryButton').simulate('click');
});
component.update();
const latestRequest = server.requests[server.requests.length - 1];
expect(latestRequest.method).toBe('POST');
expect(latestRequest.url).toBe(`${API_BASE_PATH}repositories/${repo1.name}/cleanup`);
expect(exists('repositoryDetail.cleanupCodeBlock')).toBe(false);
expect(exists('repositoryDetail.cleanupError')).toBe(true);
});
});
});
describe('when the repository has been fetched (and has snapshots)', () => {

View file

@ -356,21 +356,16 @@ export const RepositoryDetails: React.FunctionComponent<Props> = ({
</EuiCodeBlock>
</div>
) : (
<EuiCallOut
color="danger"
iconType="alert"
title={i18n.translate('xpack.snapshotRestore.repositoryDetails.cleanupErrorTitle', {
defaultMessage: 'Sorry, there was an error cleaning the repository.',
})}
>
<p>
{cleanup.error
? JSON.stringify(cleanup.error)
: i18n.translate('xpack.snapshotRestore.repositoryDetails.cleanupUnknownError', {
defaultMessage: '503: Unknown error',
})}
</p>
</EuiCallOut>
<SectionError
title={
<FormattedMessage
id="xpack.snapshotRestore.repositoryDetails.cleanupErrorTitle"
defaultMessage="Error cleaning repository"
/>
}
error={cleanup.error as Error}
data-test-subj="cleanupError"
/>
)}
</>
) : null}

View file

@ -34,7 +34,7 @@ export const wrapEsError = (err: any, statusCodeToMessageMap: any = {}) => {
root_cause = [], // eslint-disable-line @typescript-eslint/naming-convention
caused_by = {}, // eslint-disable-line @typescript-eslint/naming-convention
} = {},
} = JSON.parse(response);
} = typeof response === 'string' ? JSON.parse(response) : response;
// If no custom message if specified for the error's status code, just
// wrap the error as a Boom error response, include the additional information from ES, and return it

View file

@ -233,12 +233,21 @@ export function registerRepositoriesRoutes({
try {
const { body: cleanupResults } = await clusterClient.asCurrentUser.snapshot
.cleanupRepository({ name })
.catch((e) => ({
body: {
cleaned: false,
error: e.response ? JSON.parse(e.response) : e,
},
}));
.catch((e) => {
// This API returns errors in a non-standard format, which we'll need to
// munge to be compatible with wrapEsError.
const normalizedError = {
statusCode: e.meta.body.status,
response: e.meta.body,
};
return {
body: {
cleaned: false,
error: wrapEsError(normalizedError),
},
};
});
return res.ok({
body: {

View file

@ -23213,7 +23213,6 @@
"xpack.snapshotRestore.repositoryDetails.cleanupErrorTitle": "申し訳ありません。リポジトリのクリーンアップ中にエラーが発生しました。",
"xpack.snapshotRestore.repositoryDetails.cleanupRepositoryMessage": "スナップショットから参照されていないデータを削除するには、リポジトリをクリーンアップすることができます。これにより、ストレージ領域を解放できる場合があります。注:定期的にスナップショットを削除する場合は、この機能の利点が得られない可能性が高いため、使用頻度を低くしてください。",
"xpack.snapshotRestore.repositoryDetails.cleanupTitle": "リポジトリのクリーンアップ",
"xpack.snapshotRestore.repositoryDetails.cleanupUnknownError": "503:不明なエラー",
"xpack.snapshotRestore.repositoryDetails.closeButtonLabel": "閉じる",
"xpack.snapshotRestore.repositoryDetails.editButtonLabel": "編集",
"xpack.snapshotRestore.repositoryDetails.genericSettingsDescription": "レポジトリ「{name}」のランダムな設定です",

View file

@ -23602,7 +23602,6 @@
"xpack.snapshotRestore.repositoryDetails.cleanupErrorTitle": "抱歉,清理存储库时出错。",
"xpack.snapshotRestore.repositoryDetails.cleanupRepositoryMessage": "您可以清理存储库,以从快照中删除任何未引用的数据。这可节省存储空间。注意:如果定时删除快照,此功能可能并不那么有用,不应频繁使用。",
"xpack.snapshotRestore.repositoryDetails.cleanupTitle": "存储库清理",
"xpack.snapshotRestore.repositoryDetails.cleanupUnknownError": "503未知错误",
"xpack.snapshotRestore.repositoryDetails.closeButtonLabel": "关闭",
"xpack.snapshotRestore.repositoryDetails.editButtonLabel": "编辑",
"xpack.snapshotRestore.repositoryDetails.genericSettingsDescription": "存储库“{name}”的只读设置",