Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pause and Resume #549

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
15 changes: 15 additions & 0 deletions src/js/ZenkoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,28 @@ class ZenkoClient extends S3Client implements ZenkoClientInterface {
.promise();
}

pauseCrrSite(site: Site): Promise<ZenkoMapResp> {
const params = {
Site: site,
};

return this._jsonClient.pauseSite(params).promise();
}

pauseIngestionSite(site: Site): Promise<ZenkoMapResp> {
const params = {
Site: site,
};
return this._jsonClient.pauseIngestionSite(params).promise();
}

resumeCrrSite(site: Site): Promise<ZenkoMapResp> {
const params = {
Site: site,
};
return this._jsonClient.resumeSite(params).promise();
}

resumeIngestionSite(site: Site): Promise<ZenkoMapResp> {
const params = {
Site: site,
Expand Down
64 changes: 35 additions & 29 deletions src/react/actions/zenko.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import { LIST_OBJECT_VERSIONS_S3_TYPE } from '../utils/s3';
import { ListObjectsType } from '../../types/s3';
export const NETWORK_START_ACTION_STARTING_SEARCH = 'Starting search';
export const NETWORK_START_ACTION_SEARCHING_OBJECTS = 'Searching objects';
export const NETWORK_START_ACTION_SEARCHING_NEXT_OBJECTS = 'Loading next page of objects matching your search';
export const NETWORK_START_ACTION_SEARCHING_NEXT_OBJECTS =
'Loading next page of objects matching your search';
export const NETWORK_START_ACTION_SEARCHING_VERSIONS = 'Searching versions';
export const NETWORK_START_ACTION_CONTINUE_SEARCH = 'Continue search';

Expand Down Expand Up @@ -106,38 +107,42 @@ function _getSearchObjects(
}
return zenkoClient
.searchBucket(params)
.then(async ({ IsTruncated, NextContinuationToken, Contents }: SearchBucketResp) => {
const nextMarker = (IsTruncated && NextContinuationToken) || null;
.then(
async ({
IsTruncated,
NextContinuationToken,
Contents,
}: SearchBucketResp) => {
const nextMarker = (IsTruncated && NextContinuationToken) || null;

const list = await Promise.all(
(Contents || []).map(async (object) => {
object.IsFolder = _isFolder(object.Key);
const list = await Promise.all(
(Contents || []).map(async (object) => {
object.IsFolder = _isFolder(object.Key);

if (!object.IsFolder) {
object.SignedUrl = zenkoClient.getObjectSignedUrl(
bucketName,
object.Key,
);
object.ObjectRetention = await zenkoClient.getObjectRetention(
bucketName,
object.Key,
);
object.IsLegalHoldEnabled = await zenkoClient.getObjectLegalHold(
bucketName,
object.Key,
);
}
if (!object.IsFolder) {
object.SignedUrl = zenkoClient.getObjectSignedUrl(
bucketName,
object.Key,
);
object.ObjectRetention = await zenkoClient.getObjectRetention(
bucketName,
object.Key,
);
object.IsLegalHoldEnabled =
await zenkoClient.getObjectLegalHold(bucketName, object.Key);
}

return object;
}),
);
return object;
}),
);

if (marker) {
dispatch(appendSearchListing(nextMarker, list));
} else {
dispatch(writeSearchListing(nextMarker, list));
}
})
if (marker) {
dispatch(appendSearchListing(nextMarker, list));
} else {
dispatch(writeSearchListing(nextMarker, list));
}
},
)
.catch((err) => dispatch(zenkoHandleError(err, null, null)))
.finally(() => dispatch(networkEnd()));
};
Expand Down Expand Up @@ -301,6 +306,7 @@ export function waitForIngestionUpdate(
(next) => dispatch(loadInstanceLatestStatus()).then(next),
);
}

export function pauseIngestionSite(site: Site): ThunkStatePromisedAction {
return (dispatch: DispatchFunction, getState: GetStateFunction) => {
const { zenkoClient } = getClients(getState());
Expand Down
69 changes: 41 additions & 28 deletions src/react/backend/location/Locations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,29 @@ import { HelpLocationTargetBucket } from '../../ui-elements/Help';
import {
canDeleteLocation,
canEditLocation,
IngestionCell,
} from '../../backend/location/utils';
import { deleteLocation } from '../../actions';
import { deleteLocation, handleClientError, networkEnd } from '../../actions';
import { useDispatch, useSelector } from 'react-redux';
import type { AppState } from '../../../types/state';

import DeleteConfirmation from '../../ui-elements/DeleteConfirmation';
import { Warning } from '../../ui-elements/Warning';
import { push } from 'connected-react-router';
import { XDM_FEATURE } from '../../../js/config';
import { TitleRow as TableHeader } from '../../ui-elements/TableKeyValue';
import { Table, Button } from '@scality/core-ui/dist/next';
import { Table, Button, Box } from '@scality/core-ui/dist/next';
import { useHistory } from 'react-router-dom';
import { CellProps } from 'react-table';
import { useWorkflows } from '../../workflow/Workflows';
import { InlineButton } from '../../ui-elements/Table';
import ColdStorageIcon from '../../ui-elements/ColdStorageIcon';
import { getLocationType } from '../../utils/storageOptions';
import { BucketWorkflowTransitionV2 } from '../../../js/managementClient/api';
import { Icon } from '@scality/core-ui';
import { Icon, IconHelp } from '@scality/core-ui';
import { PauseAndResume } from './PauseAndResume';

type LocationRowProps = {
original: Location;
};

const ActionButtons = ({
rowValues,
Expand Down Expand Up @@ -120,13 +124,7 @@ function Locations() {
const loading = useSelector(
(state: AppState) => state.networkActivity.counter > 0,
);
const ingestionStates = useSelector(
(state: AppState) =>
state.instanceStatus.latest.metrics?.['ingest-schedule']?.states,
);
const capabilities = useSelector(
(state: AppState) => state.instanceStatus.latest.state.capabilities,
);

const features = useSelector((state: AppState) => state.auth.config.features);
const SEARCH_QUERY_PARAM = 'search';
const columns = useMemo(() => {
Expand Down Expand Up @@ -162,8 +160,7 @@ function Locations() {
{
Header: (
<>
Target Bucket{' '}
<HelpLocationTargetBucket />
Target Bucket <HelpLocationTargetBucket />
</>
),
accessor: 'details.bucketName',
Expand All @@ -174,18 +171,36 @@ function Locations() {
},
];

if (features.includes(XDM_FEATURE)) {
columns.push({
Header: 'Async Metadata updates',
accessor: '_asyncMetadataUpdatesColumn',
disableSortBy: true,
cellStyle: {
textAlign: 'left',
minWidth: '12rem',
},
Cell: IngestionCell(ingestionStates, capabilities, loading, dispatch),
});
}
columns.push({
Header: (
<>
Workflow status{' '}
<IconHelp
placement="top"
overlayStyle={{ width: '24rem' }}
tooltipMessage={
<>
Pausing the Workflow statuses will halt any workflow processes,
including asynchronous metadata updates and replication, that
are targeting this location.
<br /> <br />
Any new object added to the source location will be queued and
processed only once the Workflow processes are resumed.
</>
}
/>
</>
),
accessor: '_asyncMetadataUpdatesColumn',
disableSortBy: true,
cellStyle: {
textAlign: 'left',
minWidth: '14rem',
},
Cell: ({ row: { original } }: { row: LocationRowProps }) => (
<PauseAndResume locationName={original.name} />
),
});

columns.push({
Header: '',
Expand Down Expand Up @@ -219,9 +234,7 @@ function Locations() {
buckets,
endpoints,
workflowsQuery.data?.replications,
ingestionStates,
loading,
capabilities,
features,
]);
if (Object.keys(locations).length === 0) {
Expand Down
Loading