Skip to content

Commit

Permalink
feat: [WD-19698] Custom ISO permission check.
Browse files Browse the repository at this point in the history
- Custom ISO - can delete
- Codebase refactor.

Signed-off-by: Nkeiruka <[email protected]>
  • Loading branch information
Kxiru committed Feb 26, 2025
1 parent 3fd8cb2 commit 914a058
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 279 deletions.
262 changes: 0 additions & 262 deletions src/api/storage-pools.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
import {
constructMemberError,
handleEtagResponse,
handleResponse,
handleSettledResult,
} from "util/helpers";
import {
LxdStoragePool,
LXDStoragePoolOnClusterMember,
LxdStoragePoolResources,
LxdStorageVolume,
LxdStorageVolumeState,
UploadState,
} from "types/storage";
import type { LxdApiResponse } from "types/apiResponse";
import type { LxdOperationResponse } from "types/operation";
import axios, { AxiosResponse } from "axios";
import type { LxdClusterMember } from "types/cluster";
import { ClusterSpecificValues } from "components/ClusterSpecificSelect";
import { withEntitlementsQuery } from "util/entitlements/api";

export const storagePoolEntitlements = ["can_edit", "can_delete"];
export const storageVolumeEntitlements = ["can_delete"];

export const fetchStoragePool = (
pool: string,
Expand Down Expand Up @@ -247,258 +240,3 @@ export const fetchPoolFromClusterMembers = (
.catch(reject);
});
};

export const fetchStorageVolumes = (
pool: string,
project: string,
isFineGrained: boolean | null,
): Promise<LxdStorageVolume[]> => {
const entitlements = withEntitlementsQuery(
isFineGrained,
storageVolumeEntitlements,
);
return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${pool}/volumes?project=${project}&recursion=1${entitlements}`,
)
.then(handleResponse)
.then((data: LxdApiResponse<LxdStorageVolume[]>) =>
resolve(data.metadata.map((volume) => ({ ...volume, pool }))),
)
.catch(reject);
});
};

export const fetchAllStorageVolumes = (
project: string,
isFineGrained: boolean | null,
): Promise<LxdStorageVolume[]> => {
const entitlements = withEntitlementsQuery(
isFineGrained,
storageVolumeEntitlements,
);
return new Promise((resolve, reject) => {
fetch(`/1.0/storage-volumes?recursion=1&project=${project}${entitlements}`)
.then(handleResponse)
.then((data: LxdApiResponse<LxdStorageVolume[]>) =>
resolve(data.metadata),
)
.catch(reject);
});
};

export const fetchStorageVolume = (
pool: string,
project: string,
type: string,
volume: string,
isFineGrained: boolean | null,
): Promise<LxdStorageVolume> => {
const entitlements = withEntitlementsQuery(
isFineGrained,
storageVolumeEntitlements,
);
return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${pool}/volumes/${type}/${volume}?project=${project}&recursion=1${entitlements}`,
)
.then(handleEtagResponse)
.then((data) => resolve({ ...data, pool } as LxdStorageVolume))
.catch(reject);
});
};

export const fetchStorageVolumeState = (
pool: string,
project: string,
type: string,
volume: string,
): Promise<LxdStorageVolumeState> => {
return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${pool}/volumes/${type}/${volume}/state?project=${project}&recursion=1`,
)
.then(handleResponse)
.then((data: LxdApiResponse<LxdStorageVolumeState>) =>
resolve(data.metadata),
)
.catch(reject);
});
};

export const renameStorageVolume = (
project: string,
volume: LxdStorageVolume,
newName: string,
): Promise<void> => {
return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${volume.pool}/volumes/${volume.type}/${volume.name}?project=${project}`,
{
method: "POST",
body: JSON.stringify({
name: newName,
}),
},
)
.then(handleResponse)
.then(resolve)
.catch(reject);
});
};

export const createIsoStorageVolume = (
pool: string,
isoFile: File,
name: string,
project: string,
setUploadState: (value: UploadState) => void,
uploadController: AbortController,
): Promise<LxdOperationResponse> => {
return new Promise((resolve, reject) => {
axios
.post(
`/1.0/storage-pools/${pool}/volumes/custom?project=${project}`,
isoFile,
{
headers: {
"Content-Type": "application/octet-stream",
"X-LXD-name": name,
"X-LXD-type": "iso",
},
onUploadProgress: (event) => {
setUploadState({
percentage: event.progress ? Math.floor(event.progress * 100) : 0,
loaded: event.loaded,
total: event.total,
});
},
signal: uploadController.signal,
},
)
.then((response: AxiosResponse<LxdOperationResponse>) => response.data)
.then(resolve)
.catch(reject);
});
};

export const createStorageVolume = (
pool: string,
project: string,
volume: Partial<LxdStorageVolume>,
target?: string,
): Promise<void> => {
const targetParam = target ? `&target=${target}` : "";

return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${pool}/volumes?project=${project}${targetParam}`,
{
method: "POST",
body: JSON.stringify(volume),
},
)
.then(handleResponse)
.then(resolve)
.catch(reject);
});
};

export const updateStorageVolume = (
pool: string,
project: string,
volume: Partial<LxdStorageVolume>,
): Promise<void> => {
return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${pool}/volumes/${volume.type ?? ""}/${
volume.name ?? ""
}?project=${project}`,
{
method: "PUT",
body: JSON.stringify(volume),
headers: {
"If-Match": volume.etag ?? "invalid-etag",
},
},
)
.then(handleResponse)
.then(resolve)
.catch(reject);
});
};

export const deleteStorageVolume = (
volume: string,
pool: string,
project: string,
): Promise<void> => {
return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${pool}/volumes/custom/${volume}?project=${project}`,
{
method: "DELETE",
},
)
.then(handleResponse)
.then(resolve)
.catch(reject);
});
};

export const migrateStorageVolume = (
volume: Partial<LxdStorageVolume>,
targetPool: string,
targetProject: string,
): Promise<LxdOperationResponse> => {
return new Promise((resolve, reject) => {
fetch(
`/1.0/storage-pools/${volume.pool}/volumes/custom/${volume.name}?project=${targetProject}`,
{
method: "POST",
body: JSON.stringify({
name: volume.name,
pool: targetPool,
}),
},
)
.then(handleResponse)
.then(resolve)
.catch(reject);
});
};

// Including project and target params if they did not change from source configs breaks the API call.
// Therefore, we only include them if they are different from the source configs, that's why both project and target are optional inputs
export const duplicateStorageVolume = (
volume: Partial<LxdStorageVolume>,
pool: string,
project?: string,
target?: string,
): Promise<LxdOperationResponse> => {
return new Promise((resolve, reject) => {
const url = new URL(
`/1.0/storage-pools/${pool}/volumes/custom`,
window.location.origin,
);
const params = new URLSearchParams();

if (project) {
params.append("project", project);
}

if (target) {
params.append("target", target);
}

url.search = params.toString();

fetch(url.toString(), {
method: "POST",
body: JSON.stringify(volume),
})
.then(handleResponse)
.then(resolve)
.catch(reject);
});
};
Loading

0 comments on commit 914a058

Please sign in to comment.