E2C: Show snapshot error status (#91214)
* wip getError fn * Create show errors from all API requests * suppress error toasts from all e2c endpoints * require error severity
This commit is contained in:
@@ -18,7 +18,7 @@ function createBackendSrvBaseQuery({ baseURL }: { baseURL: string }): BaseQueryF
|
||||
getBackendSrv().fetch({
|
||||
...requestOptions,
|
||||
url: baseURL + requestOptions.url,
|
||||
showErrorAlert: requestOptions.showErrorAlert,
|
||||
showErrorAlert: false,
|
||||
data: requestOptions.body,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -8,50 +8,39 @@ export const cloudMigrationAPI = generatedAPI.enhanceEndpoints({
|
||||
|
||||
endpoints: {
|
||||
// Cloud-side - create token
|
||||
getCloudMigrationToken(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.providesTags = ['cloud-migration-token'];
|
||||
getCloudMigrationToken: {
|
||||
providesTags: ['cloud-migration-token'],
|
||||
},
|
||||
createCloudMigrationToken(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.invalidatesTags = ['cloud-migration-token'];
|
||||
createCloudMigrationToken: {
|
||||
invalidatesTags: ['cloud-migration-token'],
|
||||
},
|
||||
deleteCloudMigrationToken(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.invalidatesTags = ['cloud-migration-token'];
|
||||
deleteCloudMigrationToken: {
|
||||
invalidatesTags: ['cloud-migration-token'],
|
||||
},
|
||||
|
||||
// List Cloud Configs
|
||||
// On-prem session management (entering token)
|
||||
getSessionList: {
|
||||
providesTags: ['cloud-migration-session'] /* should this be a -list? */,
|
||||
},
|
||||
|
||||
// Create Cloud Config
|
||||
createSession(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.invalidatesTags = ['cloud-migration-session'];
|
||||
},
|
||||
|
||||
// Get one Cloud Config
|
||||
getSession: {
|
||||
providesTags: ['cloud-migration-session'],
|
||||
},
|
||||
|
||||
// Delete one Cloud Config
|
||||
createSession: {
|
||||
invalidatesTags: ['cloud-migration-session'],
|
||||
},
|
||||
deleteSession: {
|
||||
invalidatesTags: ['cloud-migration-session', 'cloud-migration-snapshot'],
|
||||
},
|
||||
|
||||
// Snapshot management
|
||||
getSnapshot: {
|
||||
providesTags: ['cloud-migration-snapshot'],
|
||||
},
|
||||
getShapshotList: {
|
||||
providesTags: ['cloud-migration-snapshot'],
|
||||
},
|
||||
createSnapshot(endpoint) {
|
||||
suppressErrorsOnQuery(endpoint);
|
||||
endpoint.invalidatesTags = ['cloud-migration-snapshot'];
|
||||
getSnapshot: {
|
||||
providesTags: ['cloud-migration-snapshot'],
|
||||
},
|
||||
createSnapshot: {
|
||||
invalidatesTags: ['cloud-migration-snapshot'],
|
||||
},
|
||||
uploadSnapshot: {
|
||||
invalidatesTags: ['cloud-migration-snapshot'],
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { skipToken } from '@reduxjs/toolkit/query/react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { Alert, Box, Stack, Text } from '@grafana/ui';
|
||||
import { AlertVariant, Box, Stack, Text } from '@grafana/ui';
|
||||
import { Trans, t } from 'app/core/internationalization';
|
||||
|
||||
import {
|
||||
GetSnapshotResponseDto,
|
||||
SnapshotDto,
|
||||
useCancelSnapshotMutation,
|
||||
useCreateSnapshotMutation,
|
||||
@@ -81,10 +82,12 @@ function useGetLatestSnapshot(sessionUid?: string, page = 1) {
|
||||
skipPollingIfUnfocused: true,
|
||||
});
|
||||
|
||||
const isError = listResult.isError || snapshotResult.isError;
|
||||
|
||||
useEffect(() => {
|
||||
const shouldPoll = SHOULD_POLL_STATUSES.includes(snapshotResult.data?.status);
|
||||
const shouldPoll = !isError && SHOULD_POLL_STATUSES.includes(snapshotResult.data?.status);
|
||||
setShouldPoll(shouldPoll);
|
||||
}, [snapshotResult?.data?.status]);
|
||||
}, [snapshotResult?.data?.status, isError]);
|
||||
|
||||
return {
|
||||
...snapshotResult,
|
||||
@@ -100,7 +103,7 @@ function useGetLatestSnapshot(sessionUid?: string, page = 1) {
|
||||
|
||||
// isSuccess and isUninitialised should always be from snapshotResult
|
||||
// as only the 'final' values from those are important
|
||||
isError: listResult.isError || snapshotResult.isError,
|
||||
isError,
|
||||
isLoading: listResult.isLoading || snapshotResult.isLoading,
|
||||
isFetching: listResult.isFetching || snapshotResult.isFetching,
|
||||
};
|
||||
@@ -131,11 +134,22 @@ export const Page = () => {
|
||||
snapshot.isLoading ||
|
||||
disconnectResult.isLoading;
|
||||
|
||||
const showBuildSnapshot = !snapshot.isLoading && !snapshot.data;
|
||||
const showBuildSnapshot = !snapshot.isError && !snapshot.isLoading && !snapshot.data;
|
||||
const showBuildingSnapshot = SNAPSHOT_BUILDING_STATUSES.includes(status);
|
||||
const showUploadSnapshot = status === 'PENDING_UPLOAD' || SNAPSHOT_UPLOADING_STATUSES.includes(status);
|
||||
const showUploadSnapshot =
|
||||
!snapshot.isError && (status === 'PENDING_UPLOAD' || SNAPSHOT_UPLOADING_STATUSES.includes(status));
|
||||
const showRebuildSnapshot = SNAPSHOT_REBUILD_STATUSES.includes(status);
|
||||
|
||||
const error = getError({
|
||||
snapshot: snapshot.data,
|
||||
getSnapshotError: snapshot.error,
|
||||
getSessionError: session.error,
|
||||
createSnapshotError: createSnapshotResult.error,
|
||||
uploadSnapshotError: uploadSnapshotResult.error,
|
||||
cancelSnapshotError: cancelSnapshotResult.error,
|
||||
disconnectSnapshotError: disconnectResult.error,
|
||||
});
|
||||
|
||||
const handleDisconnect = useCallback(async () => {
|
||||
if (sessionUid) {
|
||||
performDisconnect({ uid: sessionUid });
|
||||
@@ -173,34 +187,7 @@ export const Page = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Stack direction="column" gap={4}>
|
||||
{/* TODO: show errors from all mutation's in a... modal? */}
|
||||
|
||||
{createSnapshotResult.isError && (
|
||||
<AlertWithTraceID
|
||||
error={createSnapshotResult.error}
|
||||
severity="error"
|
||||
title={t('migrate-to-cloud.summary.run-migration-error-title', 'Error creating snapshot')}
|
||||
>
|
||||
<Text element="p">
|
||||
<Trans i18nKey="migrate-to-cloud.summary.run-migration-error-description">
|
||||
See the Grafana server logs for more details
|
||||
</Trans>
|
||||
</Text>
|
||||
</AlertWithTraceID>
|
||||
)}
|
||||
|
||||
{disconnectResult.isError && (
|
||||
<Alert
|
||||
severity="error"
|
||||
title={t('migrate-to-cloud.summary.disconnect-error-title', 'There was an error disconnecting')}
|
||||
>
|
||||
<Trans i18nKey="migrate-to-cloud.summary.disconnect-error-description">
|
||||
See the Grafana server logs for more details
|
||||
</Trans>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Stack direction="column" gap={2}>
|
||||
{session.data && (
|
||||
<MigrationSummary
|
||||
session={session.data}
|
||||
@@ -218,6 +205,12 @@ export const Page = () => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<AlertWithTraceID severity={error.severity} title={error.title} error={error.error}>
|
||||
<Text element="p">{error.body}</Text>
|
||||
</AlertWithTraceID>
|
||||
)}
|
||||
|
||||
{(showBuildSnapshot || showBuildingSnapshot) && (
|
||||
<Box display="flex" justifyContent="center" paddingY={10}>
|
||||
{showBuildSnapshot && (
|
||||
@@ -258,3 +251,113 @@ export const Page = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
interface GetErrorProps {
|
||||
snapshot: GetSnapshotResponseDto | undefined;
|
||||
getSessionError: unknown; // From getLatestSessionQuery
|
||||
getSnapshotError: unknown; // From getLatestSnapshotQuery
|
||||
createSnapshotError: unknown; // From createSnapshotMutation
|
||||
uploadSnapshotError: unknown; // From uploadSnapshotMutation
|
||||
cancelSnapshotError: unknown; // From cancelSnapshotMutation
|
||||
disconnectSnapshotError: unknown; // From disconnectMutation
|
||||
}
|
||||
|
||||
interface ErrorDescription {
|
||||
title: string;
|
||||
body: string;
|
||||
severity: AlertVariant;
|
||||
error?: unknown;
|
||||
}
|
||||
|
||||
function getError(props: GetErrorProps): ErrorDescription | undefined {
|
||||
const {
|
||||
snapshot,
|
||||
getSnapshotError,
|
||||
getSessionError,
|
||||
createSnapshotError,
|
||||
uploadSnapshotError,
|
||||
cancelSnapshotError,
|
||||
disconnectSnapshotError,
|
||||
} = props;
|
||||
|
||||
const seeLogs = t('migrate-to-cloud.onprem.error-see-server-logs', 'See the Grafana server logs for more details');
|
||||
|
||||
if (getSessionError) {
|
||||
return {
|
||||
severity: 'error',
|
||||
title: t('migrate-to-cloud.onprem.get-session-error-title', 'Error loading migration configuration'),
|
||||
body: seeLogs,
|
||||
error: getSessionError,
|
||||
};
|
||||
}
|
||||
|
||||
if (getSnapshotError) {
|
||||
return {
|
||||
severity: 'error',
|
||||
title: t('migrate-to-cloud.onprem.get-snapshot-error-title', 'Error loading snapshot'),
|
||||
body: seeLogs,
|
||||
error: getSnapshotError,
|
||||
};
|
||||
}
|
||||
|
||||
if (disconnectSnapshotError) {
|
||||
return {
|
||||
severity: 'warning',
|
||||
title: t('migrate-to-cloud.onprem.disconnect-error-title', 'Error disconnecting'),
|
||||
body: seeLogs,
|
||||
error: disconnectSnapshotError,
|
||||
};
|
||||
}
|
||||
|
||||
if (createSnapshotError) {
|
||||
return {
|
||||
severity: 'warning',
|
||||
title: t('migrate-to-cloud.onprem.create-snapshot-error-title', 'Error creating snapshot'),
|
||||
body: seeLogs,
|
||||
error: createSnapshotError,
|
||||
};
|
||||
}
|
||||
|
||||
if (uploadSnapshotError) {
|
||||
return {
|
||||
severity: 'warning',
|
||||
title: t('migrate-to-cloud.onprem.upload-snapshot-error-title', 'Error uploading snapshot'),
|
||||
body: seeLogs,
|
||||
error: uploadSnapshotError,
|
||||
};
|
||||
}
|
||||
|
||||
if (cancelSnapshotError) {
|
||||
return {
|
||||
severity: 'warning',
|
||||
title: t('migrate-to-cloud.onprem.cancel-snapshot-error-title', 'Error cancelling creating snapshot'),
|
||||
body: seeLogs,
|
||||
error: cancelSnapshotError,
|
||||
};
|
||||
}
|
||||
|
||||
if (snapshot?.status === 'ERROR') {
|
||||
return {
|
||||
severity: 'warning',
|
||||
title: t('migrate-to-cloud.onprem.snapshot-error-status-title', 'Error migrating resources'),
|
||||
body: t(
|
||||
'migrate-to-cloud.onprem.snapshot-error-status-body',
|
||||
'There was an error creating the snapshot or starting the migration process. See the Grafana server logs for more details'
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const errorCount = snapshot?.stats?.statuses?.['ERROR'] ?? 0;
|
||||
if (snapshot?.status === 'FINISHED' && errorCount > 0) {
|
||||
return {
|
||||
severity: 'warning',
|
||||
title: t('migrate-to-cloud.onprem.some-resources-errored-title', 'Resource migration complete'),
|
||||
body: t(
|
||||
'migrate-to-cloud.onprem.some-resources-errored-body',
|
||||
'The migration has completed, but some items could not be migrated to the cloud stack. Check the failed resources for more details'
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -15,9 +15,13 @@ export function AlertWithTraceID(props: AlertWithTraceIDProps) {
|
||||
<Stack direction="column" gap={1}>
|
||||
{children}
|
||||
|
||||
{/* Deliberately don't want to translate 'Trace ID' */}
|
||||
{/* eslint-disable-next-line @grafana/no-untranslated-strings */}
|
||||
{traceID && <Text element="p">Trace ID: {traceID}</Text>}
|
||||
{traceID && (
|
||||
/* Deliberately don't want to translate 'Trace ID' */
|
||||
/* eslint-disable-next-line @grafana/no-untranslated-strings */
|
||||
<Text element="p" color="secondary" variant="bodySmall">
|
||||
Trace ID: {traceID}
|
||||
</Text>
|
||||
)}
|
||||
</Stack>
|
||||
</Alert>
|
||||
);
|
||||
|
||||
@@ -1111,6 +1111,19 @@
|
||||
"modal-title": "Migration token created",
|
||||
"status": "Current status: <2></2>"
|
||||
},
|
||||
"onprem": {
|
||||
"cancel-snapshot-error-title": "Error cancelling creating snapshot",
|
||||
"create-snapshot-error-title": "Error creating snapshot",
|
||||
"disconnect-error-title": "Error disconnecting",
|
||||
"error-see-server-logs": "See the Grafana server logs for more details",
|
||||
"get-session-error-title": "Error loading migration configuration",
|
||||
"get-snapshot-error-title": "Error loading snapshot",
|
||||
"snapshot-error-status-body": "There was an error creating the snapshot or starting the migration process. See the Grafana server logs for more details",
|
||||
"snapshot-error-status-title": "Error migrating resources",
|
||||
"some-resources-errored-body": "The migration has completed, but some items could not be migrated to the cloud stack. Check the failed resources for more details",
|
||||
"some-resources-errored-title": "Resource migration complete",
|
||||
"upload-snapshot-error-title": "Error uploading snapshot"
|
||||
},
|
||||
"pdc": {
|
||||
"body": "Exposing your data sources to the internet can raise security concerns. Private data source connect (PDC) allows Grafana Cloud to access your existing data sources over a secure network tunnel.",
|
||||
"link-title": "Learn about PDC",
|
||||
@@ -1154,13 +1167,9 @@
|
||||
"summary": {
|
||||
"cancel-snapshot": "Cancel snapshot",
|
||||
"disconnect": "Disconnect",
|
||||
"disconnect-error-description": "See the Grafana server logs for more details",
|
||||
"disconnect-error-title": "There was an error disconnecting",
|
||||
"errored-resource-count": "Errors",
|
||||
"page-loading": "Loading...",
|
||||
"rebuild-snapshot": "Rebuild snapshot",
|
||||
"run-migration-error-description": "See the Grafana server logs for more details",
|
||||
"run-migration-error-title": "Error creating snapshot",
|
||||
"snapshot-date": "Snapshot timestamp",
|
||||
"snapshot-not-created": "Not yet created",
|
||||
"start-migration": "Build snapshot",
|
||||
|
||||
@@ -1111,6 +1111,19 @@
|
||||
"modal-title": "Mįģřäŧįőʼn ŧőĸęʼn čřęäŧęđ",
|
||||
"status": "Cūřřęʼnŧ şŧäŧūş: <2></2>"
|
||||
},
|
||||
"onprem": {
|
||||
"cancel-snapshot-error-title": "Ēřřőř čäʼnčęľľįʼnģ čřęäŧįʼnģ şʼnäpşĥőŧ",
|
||||
"create-snapshot-error-title": "Ēřřőř čřęäŧįʼnģ şʼnäpşĥőŧ",
|
||||
"disconnect-error-title": "Ēřřőř đįşčőʼnʼnęčŧįʼnģ",
|
||||
"error-see-server-logs": "Ŝęę ŧĥę Ğřäƒäʼnä şęřvęř ľőģş ƒőř mőřę đęŧäįľş",
|
||||
"get-session-error-title": "Ēřřőř ľőäđįʼnģ mįģřäŧįőʼn čőʼnƒįģūřäŧįőʼn",
|
||||
"get-snapshot-error-title": "Ēřřőř ľőäđįʼnģ şʼnäpşĥőŧ",
|
||||
"snapshot-error-status-body": "Ŧĥęřę ŵäş äʼn ęřřőř čřęäŧįʼnģ ŧĥę şʼnäpşĥőŧ őř şŧäřŧįʼnģ ŧĥę mįģřäŧįőʼn přőčęşş. Ŝęę ŧĥę Ğřäƒäʼnä şęřvęř ľőģş ƒőř mőřę đęŧäįľş",
|
||||
"snapshot-error-status-title": "Ēřřőř mįģřäŧįʼnģ řęşőūřčęş",
|
||||
"some-resources-errored-body": "Ŧĥę mįģřäŧįőʼn ĥäş čőmpľęŧęđ, þūŧ şőmę įŧęmş čőūľđ ʼnőŧ þę mįģřäŧęđ ŧő ŧĥę čľőūđ şŧäčĸ. Cĥęčĸ ŧĥę ƒäįľęđ řęşőūřčęş ƒőř mőřę đęŧäįľş",
|
||||
"some-resources-errored-title": "Ŗęşőūřčę mįģřäŧįőʼn čőmpľęŧę",
|
||||
"upload-snapshot-error-title": "Ēřřőř ūpľőäđįʼnģ şʼnäpşĥőŧ"
|
||||
},
|
||||
"pdc": {
|
||||
"body": "Ēχpőşįʼnģ yőūř đäŧä şőūřčęş ŧő ŧĥę įʼnŧęřʼnęŧ čäʼn řäįşę şęčūřįŧy čőʼnčęřʼnş. Přįväŧę đäŧä şőūřčę čőʼnʼnęčŧ (PĐC) äľľőŵş Ğřäƒäʼnä Cľőūđ ŧő äččęşş yőūř ęχįşŧįʼnģ đäŧä şőūřčęş ővęř ä şęčūřę ʼnęŧŵőřĸ ŧūʼnʼnęľ.",
|
||||
"link-title": "Ŀęäřʼn äþőūŧ PĐC",
|
||||
@@ -1154,13 +1167,9 @@
|
||||
"summary": {
|
||||
"cancel-snapshot": "Cäʼnčęľ şʼnäpşĥőŧ",
|
||||
"disconnect": "Đįşčőʼnʼnęčŧ",
|
||||
"disconnect-error-description": "Ŝęę ŧĥę Ğřäƒäʼnä şęřvęř ľőģş ƒőř mőřę đęŧäįľş",
|
||||
"disconnect-error-title": "Ŧĥęřę ŵäş äʼn ęřřőř đįşčőʼnʼnęčŧįʼnģ",
|
||||
"errored-resource-count": "Ēřřőřş",
|
||||
"page-loading": "Ŀőäđįʼnģ...",
|
||||
"rebuild-snapshot": "Ŗęþūįľđ şʼnäpşĥőŧ",
|
||||
"run-migration-error-description": "Ŝęę ŧĥę Ğřäƒäʼnä şęřvęř ľőģş ƒőř mőřę đęŧäįľş",
|
||||
"run-migration-error-title": "Ēřřőř čřęäŧįʼnģ şʼnäpşĥőŧ",
|
||||
"snapshot-date": "Ŝʼnäpşĥőŧ ŧįmęşŧämp",
|
||||
"snapshot-not-created": "Ńőŧ yęŧ čřęäŧęđ",
|
||||
"start-migration": "ßūįľđ şʼnäpşĥőŧ",
|
||||
|
||||
Reference in New Issue
Block a user