-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(storage) crud for custom volume snapshots
- removed snapshot volume type from volumes list filter. - clicking on volume name will redirect to instance detail page if it's a container or vm volume, redirect to image list page if it's a image volume and redirect to volume details if it's a custom volume. - added the snapshots column to the volumes list table. Number of snapshots per volume is calculated based on number of snapshot volumes that matches each volume name. - CTA for storage volume list table. For custom storage volumes, user can add snapshots or delete volume. For instance volumes, link to instance detail and for image volumes link to images list. Show CTA only on hover volume row. - Generalised snapshot form modal - Snapshot form modal will now be rendered using portal - Added storage volume snapshot api - Create instance and custom volume snapshots using the generalised snapshot form modal - Fixed issue with snapshot form modal retaining stale states after snapshot created, this was an issue with instance snapshot as well - Implemented snapshots tab for storage volume detail page (heavy reference to the snapshots tab for instnace detail page) - Code cleanup - Fixed issue with not able to sort by the snapshots column on the storage volume list table - Fixed issue with disabling snapshot creation if project is restricted - Fixed tooltip wording for add snapshot CTA button on volume list table Signed-off-by: Mason Hu <[email protected]>
- Loading branch information
Showing
45 changed files
with
2,517 additions
and
595 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import { | ||
continueOrFinish, | ||
handleResponse, | ||
pushFailure, | ||
pushSuccess, | ||
} from "util/helpers"; | ||
import { LxdOperationResponse } from "types/operation"; | ||
import { LxdStorageVolume, LxdVolumeSnapshot } from "types/storage"; | ||
import { LxdApiResponse, LxdSyncResponse } from "types/apiResponse"; | ||
import { EventQueue } from "context/eventQueue"; | ||
|
||
export const createSnapshot = (args: { | ||
volume: LxdStorageVolume; | ||
name: string; | ||
expiresAt: string | null; | ||
}): Promise<LxdOperationResponse> => { | ||
const { volume, name, expiresAt } = args; | ||
return new Promise((resolve, reject) => { | ||
fetch( | ||
`/1.0/storage-pools/${volume.pool}/volumes/custom/${volume.name}/snapshots?project=${volume.project}`, | ||
{ | ||
method: "POST", | ||
body: JSON.stringify({ | ||
name, | ||
expires_at: expiresAt, | ||
}), | ||
}, | ||
) | ||
.then(handleResponse) | ||
.then(resolve) | ||
.catch(reject); | ||
}); | ||
}; | ||
|
||
export const deleteSnapshot = ( | ||
volume: LxdStorageVolume, | ||
snapshot: Pick<LxdVolumeSnapshot, "name">, | ||
): Promise<LxdOperationResponse> => { | ||
return new Promise((resolve, reject) => { | ||
fetch( | ||
`/1.0/storage-pools/${volume.pool}/volumes/${volume.type}/${volume.name}/snapshots/${snapshot.name}?project=${volume.project}`, | ||
{ | ||
method: "DELETE", | ||
}, | ||
) | ||
.then(handleResponse) | ||
.then(resolve) | ||
.catch(reject); | ||
}); | ||
}; | ||
|
||
export const deleteSnapshotBulk = ( | ||
volume: LxdStorageVolume, | ||
snapshotNames: string[], | ||
eventQueue: EventQueue, | ||
): Promise<PromiseSettledResult<void>[]> => { | ||
const results: PromiseSettledResult<void>[] = []; | ||
return new Promise((resolve) => { | ||
void Promise.allSettled( | ||
snapshotNames.map(async (name) => { | ||
return await deleteSnapshot(volume, { name }).then((operation) => { | ||
eventQueue.set( | ||
operation.metadata.id, | ||
() => pushSuccess(results), | ||
(msg) => pushFailure(results, msg), | ||
() => continueOrFinish(results, snapshotNames.length, resolve), | ||
); | ||
}); | ||
}), | ||
); | ||
}); | ||
}; | ||
|
||
// NOTE: this api endpoint results in a synchronous operation | ||
export const restoreSnapshot = ( | ||
volume: LxdStorageVolume, | ||
snapshot: LxdVolumeSnapshot, | ||
): Promise<LxdSyncResponse> => { | ||
return new Promise((resolve, reject) => { | ||
fetch( | ||
`/1.0/storage-pools/${volume.pool}/volumes/${volume.type}/${volume.name}?project=${volume.project}`, | ||
{ | ||
method: "PUT", | ||
body: JSON.stringify({ | ||
restore: snapshot.name, | ||
}), | ||
}, | ||
) | ||
.then(handleResponse) | ||
.then(resolve) | ||
.catch(reject); | ||
}); | ||
}; | ||
|
||
export const renameSnapshot = (args: { | ||
volume: LxdStorageVolume; | ||
snapshot: LxdVolumeSnapshot; | ||
newName: string; | ||
}): Promise<LxdOperationResponse> => { | ||
const { volume, snapshot, newName } = args; | ||
return new Promise((resolve, reject) => { | ||
fetch( | ||
`/1.0/storage-pools/${volume.pool}/volumes/${volume.type}/${volume.name}/snapshots/${snapshot.name}?project=${volume.project}`, | ||
{ | ||
method: "POST", | ||
body: JSON.stringify({ | ||
name: newName, | ||
}), | ||
}, | ||
) | ||
.then(handleResponse) | ||
.then(resolve) | ||
.catch(reject); | ||
}); | ||
}; | ||
|
||
// NOTE: this api endpoint results in a synchronous operation | ||
export const updateSnapshot = (args: { | ||
volume: LxdStorageVolume; | ||
snapshot: LxdVolumeSnapshot; | ||
expiresAt: string | null; | ||
description: string; | ||
}): Promise<LxdSyncResponse> => { | ||
const { volume, snapshot, expiresAt, description } = args; | ||
return new Promise((resolve, reject) => { | ||
fetch( | ||
`/1.0/storage-pools/${volume.pool}/volumes/${volume.type}/${volume.name}/snapshots/${snapshot.name}?project=${volume.project}`, | ||
{ | ||
method: "PUT", | ||
body: JSON.stringify({ | ||
expires_at: expiresAt, | ||
description: description, | ||
}), | ||
}, | ||
) | ||
.then(handleResponse) | ||
.then(resolve) | ||
.catch(reject); | ||
}); | ||
}; | ||
|
||
export const fetchStorageVolumeSnapshots = (args: { | ||
pool: string; | ||
type: string; | ||
volumeName: string; | ||
project: string; | ||
}) => { | ||
const { pool, type, volumeName, project } = args; | ||
return new Promise<LxdVolumeSnapshot[]>((resolve, reject) => { | ||
fetch( | ||
`/1.0/storage-pools/${pool}/volumes/${type}/${volumeName}/snapshots?project=${project}&recursion=2`, | ||
) | ||
.then(handleResponse) | ||
.then((data: LxdApiResponse<LxdVolumeSnapshot[]>) => | ||
resolve(data.metadata), | ||
) | ||
.catch(reject); | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React, { BaseSyntheticEvent, FC, ReactElement } from "react"; | ||
import usePortal from "react-useportal"; | ||
|
||
interface Props { | ||
renderModal: (closeModal: () => void) => ReactElement; | ||
renderButton: ( | ||
openModal: (e: BaseSyntheticEvent<object, unknown, unknown>) => void, | ||
) => ReactElement; | ||
} | ||
|
||
const PortalModalBtn: FC<Props> = ({ renderButton, renderModal }) => { | ||
const { openPortal, closePortal, isOpen, Portal } = usePortal(); | ||
|
||
const modal = renderModal(closePortal); | ||
const button = renderButton(openPortal); | ||
|
||
return ( | ||
<> | ||
{isOpen && <Portal>{modal}</Portal>} | ||
{button} | ||
</> | ||
); | ||
}; | ||
|
||
export default PortalModalBtn; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.