diff --git a/src/libs/ajax/GoogleStorage.ts b/src/libs/ajax/GoogleStorage.ts index 3df561fcd6..f986f100cb 100644 --- a/src/libs/ajax/GoogleStorage.ts +++ b/src/libs/ajax/GoogleStorage.ts @@ -76,7 +76,7 @@ const checkRequesterPaysError = async (response): Promise { - return _.includes('requester pays', responseText); + return _.includes('to user project', responseText); }; // requesterPaysError may be set on responses from requests to the GCS API that are wrapped in withRequesterPays. diff --git a/src/libs/ajax/workspaces/Workspaces.ts b/src/libs/ajax/workspaces/Workspaces.ts index 307e87e756..89880711e7 100644 --- a/src/libs/ajax/workspaces/Workspaces.ts +++ b/src/libs/ajax/workspaces/Workspaces.ts @@ -2,6 +2,7 @@ import { jsonBody } from '@terra-ui-packages/data-client-core'; import _ from 'lodash/fp'; import * as qs from 'qs'; import { authOpts } from 'src/auth/auth-session'; +import { getLocationType } from 'src/components/region-common'; import { fetchOrchestration, fetchRawls } from 'src/libs/ajax/ajax-common'; import { Entity, EntityQueryResponse } from 'src/libs/ajax/data-table-providers/DataTableProvider'; import { fetchOk } from 'src/libs/ajax/fetch/fetch-core'; @@ -173,7 +174,14 @@ export const Workspaces = (signal?: AbortSignal) => ({ checkBucketAccess: GoogleStorage(signal).checkBucketAccess, - checkBucketLocation: GoogleStorage(signal).checkBucketLocation, + checkBucketLocation: async (userProject?) => { + const res = await fetchRawls( + `${root}/bucketOptions${userProject ? `?userProject=${userProject}` : ''}`, + _.merge(authOpts(), { signal }) + ); + const obj = await res.json(); + return _.merge(obj, { locationType: getLocationType(obj.location) }); + }, details: async (fields: FieldsArg): Promise => { const res = await fetchRawls( diff --git a/src/workspaces/common/state/useWorkspace.ts b/src/workspaces/common/state/useWorkspace.ts index d242cb4689..eccb029365 100644 --- a/src/workspaces/common/state/useWorkspace.ts +++ b/src/workspaces/common/state/useWorkspace.ts @@ -22,7 +22,7 @@ export type { InitializedWorkspaceWrapper } from 'src/libs/state'; export interface StorageDetails { googleBucketLocation: string; // historically returns defaultLocation if bucket location cannot be retrieved or Azure googleBucketType: string; // historically returns locationTypes.default if bucket type cannot be retrieved or Azure - fetchedGoogleBucketLocation: 'SUCCESS' | 'ERROR' | undefined; // undefined: still fetching + fetchedGoogleBucketLocation: 'SUCCESS' | 'ERROR' | 'RPERROR' | undefined; // undefined: still fetching azureContainerRegion?: string; azureContainerUrl?: string; azureContainerSasUrl?: string; @@ -46,7 +46,7 @@ export const useWorkspace = (namespace, name): WorkspaceDetails => { const workspace = useStore(workspaceStore); const [{ location, locationType, fetchedLocation }, setGoogleStorage] = useState<{ - fetchedLocation: 'SUCCESS' | 'ERROR' | undefined; + fetchedLocation: 'SUCCESS' | 'ERROR' | 'RPERROR' | undefined; location: string; locationType: string; }>({ @@ -115,7 +115,7 @@ export const useWorkspace = (namespace, name): WorkspaceDetails => { if (responseContainsRequesterPaysError(errorText)) { // loadGoogleBucketLocation will not get called in this case because checkBucketReadAccess fails first, // but it would also fail with the requester pays error. - setGoogleStorage({ fetchedLocation: 'ERROR', location, locationType }); + setGoogleStorage({ fetchedLocation: 'RPERROR', location, locationType }); updateWorkspaceInStore(workspace, true); } else { updateWorkspaceInStore(workspace, false); @@ -145,7 +145,7 @@ export const useWorkspace = (namespace, name): WorkspaceDetails => { try { const storageDetails = await Workspaces(signal) .workspace(namespace, name) - .checkBucketLocation(workspace.workspace.googleProject, workspace.workspace.bucketName); + .checkBucketLocation(workspace.workspace.googleProject); storageDetails.fetchedLocation = 'SUCCESS'; setGoogleStorage(storageDetails); } catch (error) { diff --git a/src/workspaces/dashboard/BucketLocation.ts b/src/workspaces/dashboard/BucketLocation.ts index 3ceab72114..36ae8587f9 100644 --- a/src/workspaces/dashboard/BucketLocation.ts +++ b/src/workspaces/dashboard/BucketLocation.ts @@ -7,11 +7,10 @@ import { getRegionInfo } from 'src/components/region-common'; import { TooltipCell } from 'src/components/table'; import { Metrics } from 'src/libs/ajax/Metrics'; import { Workspaces } from 'src/libs/ajax/workspaces/Workspaces'; -import { reportError } from 'src/libs/error'; import Events, { extractWorkspaceDetails } from 'src/libs/events'; import { useCancellation } from 'src/libs/react-utils'; import { requesterPaysProjectStore } from 'src/libs/state'; -import { isBucketErrorRequesterPays, requesterPaysWrapper } from 'src/workspaces/common/requester-pays/bucket-utils'; +import { requesterPaysWrapper } from 'src/workspaces/common/requester-pays/bucket-utils'; import { RequesterPaysModal } from 'src/workspaces/common/requester-pays/RequesterPaysModal'; import { StorageDetails } from 'src/workspaces/common/state/useWorkspace'; import { GoogleWorkspace } from 'src/workspaces/utils'; @@ -36,22 +35,21 @@ export const BucketLocation = requesterPaysWrapper({ onDismiss: _.noop })((props setLoading(true); try { const { - workspace: { namespace, name, googleProject, bucketName }, + workspace: { namespace, name, googleProject }, } = workspace; - const response = await Workspaces(signal) - .workspace(namespace, name) - .checkBucketLocation(googleProject, bucketName); + const project = needsRequesterPaysProject ? requesterPaysProjectStore.get() : googleProject; + const response = await Workspaces(signal).workspace(namespace, name).checkBucketLocation(project); setBucketLocation(response); } catch (error) { - if (isBucketErrorRequesterPays(error)) { - setNeedsRequesterPaysProject(true); - } else { - reportError('Unable to get bucket location.', error); - } + // if (error) { + setNeedsRequesterPaysProject(true); + // } else { + // reportError('Unable to get bucket location.', error); + // } } finally { setLoading(false); } - }, [workspace, signal]); + }, [workspace, signal, needsRequesterPaysProject]); useEffect(() => { if (workspace?.workspaceInitialized) { @@ -60,6 +58,9 @@ export const BucketLocation = requesterPaysWrapper({ onDismiss: _.noop })((props // while storageDetails.googleBucketLocation will contain the default value. // In the case of requester pays workspaces, we wish to show the user more information in this case and allow them to link a workspace. loadGoogleBucketLocation(); + } else if (storageDetails.fetchedGoogleBucketLocation === 'RPERROR') { + setNeedsRequesterPaysProject(true); + setLoading(false); } else if (storageDetails.fetchedGoogleBucketLocation === 'SUCCESS') { setBucketLocation({ location: storageDetails.googleBucketLocation, @@ -71,6 +72,7 @@ export const BucketLocation = requesterPaysWrapper({ onDismiss: _.noop })((props }, [ loadGoogleBucketLocation, setBucketLocation, + needsRequesterPaysProject, // Explicit dependencies to avoid extra calls to loadGoogleBucketLocation workspace?.workspaceInitialized, storageDetails.fetchedGoogleBucketLocation,