Skip to content

Commit

Permalink
feat: [WD-17984] Add Pure Storage (#1047)
Browse files Browse the repository at this point in the history
## Done

- Added Pure Storage functionality

## QA

1. Run the LXD-UI:
- On the demo server via the link posted by @webteam-app below. This is
only available for PRs created by collaborators of the repo. Ask
@mas-who or @edlerd for access.
- With a local copy of this branch, [build and run as described in the
docs](../CONTRIBUTING.md#setting-up-for-development).
2. Perform the following QA steps:
- Check out the branch and in the env.local file (One must be created if
it does not already exist) add this line of code
`LXD_UI_BACKEND_IP=10.239.7.201` to have LXD point to the
Pure-Storage-supported server. One must also have the Canonical vpn
running to access this.
    - Please message @Kxiru for API Token and Gateway Credentials.
- Navigate to Create a new storage pool and attempt to create a pool
with Driver set to "Pure Storage" and "Verify Gateway" set to False (If
set to True, this will fail).
- Navigate to storage volumes and attempt to create a sotrage volume and
assign it to the "Pure storage" pool just created.

## Screenshots


![image](https://github.com/user-attachments/assets/50bd4f40-7d53-4b81-84e2-dd354629ed33)
  • Loading branch information
Kxiru authored Jan 17, 2025
2 parents 01d5804 + 19c7aba commit 3661fbe
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 12 deletions.
14 changes: 14 additions & 0 deletions src/pages/storage/forms/StoragePoolForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
cephFSDriver,
getSupportedStorageDrivers,
powerFlex,
pureStorage,
zfsDriver,
} from "util/storageOptions";
import { getPoolKey } from "util/storagePool";
Expand Down Expand Up @@ -70,6 +71,10 @@ export interface StoragePoolFormValues {
powerflex_sdt?: string;
powerflex_user_name?: string;
powerflex_user_password?: string;
pure_api_token?: string;
pure_gateway?: string;
pure_gateway_verify?: string;
pure_mode?: string;
zfs_clone_copy?: string;
zfs_export?: string;
zfs_pool_name?: string;
Expand All @@ -90,6 +95,7 @@ export const toStoragePool = (
const isCephDriver = values.driver === cephDriver;
const isCephFSDriver = values.driver === cephFSDriver;
const isPowerFlexDriver = values.driver === powerFlex;
const isPureDriver = values.driver === pureStorage;
const isZFSDriver = values.driver === zfsDriver;
const hasValidSize = values.size?.match(/^\d/);

Expand Down Expand Up @@ -129,6 +135,14 @@ export const toStoragePool = (
[getPoolKey("powerflex_user_password")]: values.powerflex_user_password,
};
}
if (isPureDriver) {
return {
[getPoolKey("pure_api_token")]: values.pure_api_token,
[getPoolKey("pure_gateway")]: values.pure_gateway,
[getPoolKey("pure_gateway_verify")]: values.pure_gateway_verify,
[getPoolKey("pure_mode")]: values.pure_mode,
};
}
if (isZFSDriver) {
return {
[getPoolKey("zfs_clone_copy")]: values.zfs_clone_copy ?? "",
Expand Down
68 changes: 67 additions & 1 deletion src/pages/storage/forms/StoragePoolFormMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
cephDriver,
getStorageDriverOptions,
powerFlex,
pureStorage,
cephFSDriver,
} from "util/storageOptions";
import { StoragePoolFormValues } from "./StoragePoolForm";
Expand All @@ -18,6 +19,7 @@ import { getCephPoolFormFields } from "util/storagePool";
import { useSettings } from "context/useSettings";
import ScrollableForm from "components/ScrollableForm";
import { ensureEditMode } from "util/instanceEdit";
import { optionTrueFalse } from "util/instanceOptions";

interface Props {
formik: FormikProps<StoragePoolFormValues>;
Expand All @@ -42,6 +44,7 @@ const StoragePoolFormMain: FC<Props> = ({ formik }) => {
const isCephFSDriver = formik.values.driver === cephFSDriver;
const isDirDriver = formik.values.driver === dirDriver;
const isPowerFlexDriver = formik.values.driver === powerFlex;
const isPureDriver = formik.values.driver === pureStorage;
const storageDriverOptions = getStorageDriverOptions(settings);

return (
Expand Down Expand Up @@ -104,6 +107,7 @@ const StoragePoolFormMain: FC<Props> = ({ formik }) => {
{!isCephDriver &&
!isCephFSDriver &&
!isDirDriver &&
!isPureDriver &&
!isPowerFlexDriver && (
<DiskSizeSelector
label="Size"
Expand All @@ -120,7 +124,7 @@ const StoragePoolFormMain: FC<Props> = ({ formik }) => {
disabled={formik.values.driver === dirDriver}
/>
)}
{!isPowerFlexDriver && (
{!isPureDriver && !isPowerFlexDriver && (
<Input
{...getFormProps("source")}
type="text"
Expand Down Expand Up @@ -203,6 +207,68 @@ const StoragePoolFormMain: FC<Props> = ({ formik }) => {
/>
</>
)}
{isPureDriver && (
<>
<Input
{...formik.getFieldProps("pure_api_token")}
type="text"
label="API token"
placeholder="Enter Pure Storage API token"
help="API token with admin access to the Pure Storage array."
onChange={(e) => {
ensureEditMode(formik);
formik.handleChange(e);
}}
required
/>
<Input
{...formik.getFieldProps("pure_gateway")}
type="text"
label="API gateway"
placeholder="Enter Pure Storage API gateway"
help="URL for the Pure Storage API."
onChange={(e) => {
ensureEditMode(formik);
formik.handleChange(e);
}}
required
/>
<Select
{...formik.getFieldProps("pure_gateway_verify")}
label="Verify gateway"
help="Whether to verify the PureStorage certificate. Set this option to false for self-signed certs, or add the cert to the OS trust store."
options={optionTrueFalse}
onChange={(e) => {
ensureEditMode(formik);
formik.handleChange(e);
}}
/>
<Select
{...formik.getFieldProps("pure_mode")}
label="Mode"
help="Whether to use nvme or iscsi to connect to Pure Storage array."
options={[
{
label: "Select option",
value: "",
disabled: true,
},
{
label: "NVME",
value: "nvme",
},
{
label: "ISCSI",
value: "iscsi",
},
]}
onChange={(e) => {
ensureEditMode(formik);
formik.handleChange(e);
}}
/>
</>
)}
</Col>
</Row>
</ScrollableForm>
Expand Down
1 change: 1 addition & 0 deletions src/pages/storage/forms/StoragePoolFormMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const CEPHFS_CONFIGURATION = "CephFS";
export const POWERFLEX = "Powerflex";
export const ZFS_CONFIGURATION = "ZFS";
export const YAML_CONFIGURATION = "YAML configuration";
export const PURE_STORAGE = "Pure Storage";

interface Props {
active: string;
Expand Down
22 changes: 12 additions & 10 deletions src/pages/storage/forms/StorageVolumeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,18 @@ const StorageVolumeForm: FC<Props> = ({ formik, section, setSection }) => {
const poolDriver =
pools.find((item) => item.name === formik.values.pool)?.driver ?? "";

const invalidFields: (keyof StorageVolumeFormValues)[] = [];
if (!driversWithFilesystemSupport.includes(poolDriver)) {
invalidFields.push(...getFilesystemVolumeFormFields());
}
if (poolDriver !== "zfs") {
invalidFields.push(...getZfsVolumeFormFields());
}
for (const field of invalidFields) {
if (formik.values[field] !== undefined) {
void formik.setFieldValue(field, undefined);
if (pools.length > 0) {
const invalidFields: (keyof StorageVolumeFormValues)[] = [];
if (!driversWithFilesystemSupport.includes(poolDriver)) {
invalidFields.push(...getFilesystemVolumeFormFields());
}
if (poolDriver !== "zfs") {
invalidFields.push(...getZfsVolumeFormFields());
}
for (const field of invalidFields) {
if (formik.values[field] !== undefined) {
void formik.setFieldValue(field, undefined);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/types/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export interface LxdMetadata {
"storage-dir": LxcConfigOptionCategories;
"storage-lvm": LxcConfigOptionCategories;
"storage-powerflex": LxcConfigOptionCategories;
"storage-pure": LxcConfigOptionCategories;
"storage-zfs": LxcConfigOptionCategories;
};
entities: LxdEntityEntitlements;
Expand Down
1 change: 1 addition & 0 deletions src/util/permissions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ describe("General util functions for permissions feature", () => {
"storage-dir": {},
"storage-lvm": {},
"storage-powerflex": {},
"storage-pure": {},
"storage-zfs": {},
},
entities: {
Expand Down
9 changes: 8 additions & 1 deletion src/util/storageOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const zfsDriver = "zfs";
export const cephDriver = "ceph";
export const cephFSDriver = "cephfs";
export const powerFlex = "powerflex";
export const pureStorage = "pure";

const storageDriverLabels: { [key: string]: string } = {
[dirDriver]: "Directory",
Expand All @@ -17,6 +18,7 @@ const storageDriverLabels: { [key: string]: string } = {
[cephDriver]: "Ceph",
[cephFSDriver]: "CephFS",
[powerFlex]: "Dell PowerFlex",
[pureStorage]: "Pure Storage",
};

export const getStorageDriverOptions = (
Expand Down Expand Up @@ -60,4 +62,9 @@ export const getSourceHelpForDriver = (driver: string) => {
return "Not available";
};

export const driversWithFilesystemSupport = [zfsDriver, lvmDriver, cephDriver];
export const driversWithFilesystemSupport = [
zfsDriver,
lvmDriver,
cephDriver,
pureStorage,
];
5 changes: 5 additions & 0 deletions src/util/storagePool.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const storagePoolFormFieldToPayloadName: Record<string, string> = {
powerflex_sdt: "powerflex.sdt",
powerflex_user_name: "powerflex.user.name",
powerflex_user_password: "powerflex.user.password",
pure_api_token: "pure.api.token",
pure_gateway: "pure.gateway",
pure_gateway_verify: "pure.gateway.verify",
pure_mode: "pure.mode",
zfs_clone_copy: "zfs.clone_copy",
zfs_export: "zfs.export",
zfs_pool_name: "zfs.pool_name",
Expand Down Expand Up @@ -54,6 +58,7 @@ const storagePoolDriverToOptionKey: Record<string, LxdConfigOptionsKeys> = {
ceph: "storage-ceph",
cephfs: "storage-cephfs",
powerflex: "storage-powerflex",
pure: "storage-pure",
};

export const storagePoolFormDriverToOptionKey = (
Expand Down
4 changes: 4 additions & 0 deletions src/util/storagePoolForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export const toStoragePoolFormValues = (
powerflex_sdt: pool.config?.["powerflex.sdt"],
powerflex_user_name: pool.config?.["powerflex.user.name"],
powerflex_user_password: pool.config?.["powerflex.user.password"],
pure_api_token: pool.config?.["pure.api.token"],
pure_gateway: pool.config?.["pure.gateway"],
pure_gateway_verify: pool.config?.["pure.gateway.verify"],
pure_mode: pool.config?.["pure.mode"],
zfs_clone_copy: pool.config?.["zfs.clone_copy"],
zfs_export: pool.config?.["zfs.export"],
zfs_pool_name: pool.config?.["zfs.pool_name"],
Expand Down

0 comments on commit 3661fbe

Please sign in to comment.