Skip to content

Commit

Permalink
Storage: Add Pure Storage storage driver (#14599)
Browse files Browse the repository at this point in the history
This PR adds `pure` storage driver for Pure Storage remote storage.
Driver supports communication over either iSCSI or NVMe/TCP.

- [x] For iSCSI, this PR is required to ensure LXD redirects `iscsiadm`
to the LXD host: canonical/lxd-pkg-snap#646
- [x] Rebase after #14710
- [x] Rebase after #14865 (for
WaitDiskSize func)
  • Loading branch information
tomponline authored Feb 4, 2025
2 parents b98b242 + 40b6b51 commit fb787af
Show file tree
Hide file tree
Showing 37 changed files with 4,565 additions and 48 deletions.
2 changes: 2 additions & 0 deletions doc/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ EBS
EKS
enablement
favicon
FlashArray
Furo
GDB
Git
GitHub
Grafana
IAM
installable
iSCSI
JSON
Juju
Kubeflow
Expand Down
12 changes: 12 additions & 0 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2587,3 +2587,15 @@ The following new pool level configuration keys have been added:
The following configuration keys have been added for volumes backed by PowerFlex:

1. {config:option}`storage-powerflex-volume-conf:block.type`

## `storage_driver_pure`

Adds a new `pure` storage driver which allows the consumption of storage volumes from a Pure Storage storage array using either iSCSI or NVMe/TCP.

The following pool level configuration keys have been added:

1. {config:option}`storage-pure-pool-conf:pure.gateway`
1. {config:option}`storage-pure-pool-conf:pure.gateway.verify`
1. {config:option}`storage-pure-pool-conf:pure.api.token`
1. {config:option}`storage-pure-pool-conf:pure.mode`
1. {config:option}`storage-pure-pool-conf:pure.target`
15 changes: 8 additions & 7 deletions doc/explanation/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The following storage drivers are supported:
- [CephFS - `cephfs`](storage-cephfs)
- [Ceph Object - `cephobject`](storage-cephobject)
- [Dell PowerFlex - `powerflex`](storage-powerflex)
- [Pure Storage - `pure`](storage-pure)

See the following how-to guides for additional information:

Expand All @@ -36,12 +37,12 @@ See the following how-to guides for additional information:
Where the LXD data is stored depends on the configuration and the selected storage driver.
Depending on the storage driver that is used, LXD can either share the file system with its host or keep its data separate.

Storage location | Directory | Btrfs | LVM | ZFS | Ceph (all) | Dell PowerFlex |
:--- | :-: | :-: | :-: | :-: | :-: | :-: |
Shared with the host | ✓ | ✓ | - | ✓ | - | - |
Dedicated disk/partition | - | ✓ | ✓ | ✓ | - | - |
Loop disk | - | ✓ | ✓ | ✓ | - | - |
Remote storage | - | - | - | - | ✓ | ✓ |
Storage location | Directory | Btrfs | LVM | ZFS | Ceph (all) | Dell PowerFlex | Pure Storage |
:--- | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
Shared with the host | ✓ | ✓ | - | ✓ | - | - | - |
Dedicated disk/partition | - | ✓ | ✓ | ✓ | - | - | - |
Loop disk | - | ✓ | ✓ | ✓ | - | - | - |
Remote storage | - | - | - | - | ✓ | ✓ | ✓ |

#### Shared with the host

Expand Down Expand Up @@ -71,7 +72,7 @@ You can increase their size (quota) though; see {ref}`storage-resize-pool`.
#### Remote storage

The `ceph`, `cephfs` and `cephobject` drivers store the data in a completely independent Ceph storage cluster that must be set up separately.
The same applies to the `powerflex` driver.
The same applies to the `powerflex` and `pure` drivers.

(storage-default-pool)=
### Default storage pool
Expand Down
31 changes: 31 additions & 0 deletions doc/howto/storage_pools.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,24 @@ Create a storage pool named `pool5` that explicitly uses the PowerFlex SDC:

lxc storage create pool5 powerflex powerflex.mode=sdc powerflex.pool=<id of sp1> powerflex.gateway=https://powerflex powerflex.user.name=lxd powerflex.user.password=foo

#### Create a Pure Storage pool

Create a storage pool named `pool1` that uses NVMe/TCP by default:

lxc storage create pool1 pure pure.gateway=https://<pure-storage-address> pure.api.token=<pure-storage-api-token>

Create a storage pool named `pool2` that uses a Pure Storage gateway with a certificate that is not trusted:

lxc storage create pool2 pure pure.gateway=https://<pure-storage-address> pure.gateway.verify=false pure.api.token=<pure-storage-api-token>

Create a storage pool named `pool3` that uses iSCSI to connect to Pure Storage array:

lxc storage create pool3 pure pure.gateway=https://<pure-storage-address> pure.api.token=<pure-storage-api-token> pure.mode=iscsi

Create a storage pool named `pool4` that uses NVMe/TCP to connect to Pure Storage array via specific target addresses:

lxc storage create pool4 pure pure.gateway=https://<pure-storage-address> pure.api.token=<pure-storage-api-token> pure.mode=iscsi pure.target=<target_address_1>,<target_address_2>

(storage-pools-cluster)=
## Create a storage pool in a cluster

Expand Down Expand Up @@ -240,6 +258,19 @@ Storage pool my-remote-pool2 pending on member vm03
Storage pool my-remote-pool2 created
```

Create a third storage pool named `my-remote-pool3` using the Pure Storage driver:

```{terminal}
:input: lxc storage create my-remote-pool3 pure --target=vm01
Storage pool my-remote-pool3 pending on member vm01
:input: lxc storage create my-remote-pool3 pure --target=vm02
Storage pool my-remote-pool3 pending on member vm02
:input: lxc storage create my-remote-pool3 pure --target=vm03
Storage pool my-remote-pool3 pending on member vm03
:input: lxc storage create my-remote-pool3 pure pure.gateway=https://<pure-storage-address> pure.api.token=<pure-storage-api-token>
Storage pool my-remote-pool3 created
```

## Configure storage pool settings

See the {ref}`storage-drivers` documentation for the available configuration options for each storage driver.
Expand Down
117 changes: 117 additions & 0 deletions doc/metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5925,6 +5925,123 @@ Specify either a cron expression (`<minute> <hour> <dom> <month> <dow>`), a comm
```

<!-- config group storage-powerflex-volume-conf end -->
<!-- config group storage-pure-pool-conf start -->
```{config:option} pure.api.token storage-pure-pool-conf
:shortdesc: "API token for Pure Storage gateway authentication"
:type: "string"

```

```{config:option} pure.gateway storage-pure-pool-conf
:shortdesc: "Address of the Pure Storage gateway"
:type: "string"

```

```{config:option} pure.gateway.verify storage-pure-pool-conf
:defaultdesc: "`true`"
:shortdesc: "Whether to verify the Pure Storage gateway's certificate"
:type: "bool"

```

```{config:option} pure.mode storage-pure-pool-conf
:defaultdesc: "the discovered mode"
:shortdesc: "How volumes are mapped to the local server"
:type: "string"
The mode to use to map Pure Storage volumes to the local server.
Supported values are `iscsi` and `nvme`.
```

```{config:option} pure.target storage-pure-pool-conf
:defaultdesc: "the discovered mode"
:shortdesc: "List of target addresses."
:type: "string"
A comma-separated list of target addresses. If empty, LXD discovers and
connects to all available targets. Otherwise, it only connects to the
specified addresses.
```

```{config:option} volume.size storage-pure-pool-conf
:defaultdesc: "`10GiB`"
:shortdesc: "Size/quota of the storage volume"
:type: "string"
Default Pure Storage volume size rounded to 512B. The minimum size is 1MiB.
```

<!-- config group storage-pure-pool-conf end -->
<!-- config group storage-pure-volume-conf start -->
```{config:option} block.filesystem storage-pure-volume-conf
:condition: "block-based volume with content type `filesystem`"
:defaultdesc: "same as `volume.block.filesystem`"
:shortdesc: "File system of the storage volume"
:type: "string"
Valid options are: `btrfs`, `ext4`, `xfs`
If not set, `ext4` is assumed.
```

```{config:option} block.mount_options storage-pure-volume-conf
:condition: "block-based volume with content type `filesystem`"
:defaultdesc: "same as `volume.block.mount_options`"
:shortdesc: "Mount options for block-backed file system volumes"
:type: "string"

```

```{config:option} size storage-pure-volume-conf
:defaultdesc: "same as `volume.size`"
:shortdesc: "Size/quota of the storage volume"
:type: "string"
Default Pure Storage volume size rounded to 512B. The minimum size is 1MiB.
```

```{config:option} snapshots.expiry storage-pure-volume-conf
:condition: "custom volume"
:defaultdesc: "same as `volume.snapshots.expiry`"
:scope: "global"
:shortdesc: "When snapshots are to be deleted"
:type: "string"
Specify an expression like `1M 2H 3d 4w 5m 6y`.
```

```{config:option} snapshots.pattern storage-pure-volume-conf
:condition: "custom volume"
:defaultdesc: "same as `volume.snapshots.pattern` or `snap%d`"
:scope: "global"
:shortdesc: "Template for the snapshot name"
:type: "string"
You can specify a naming template that is used for scheduled snapshots and unnamed snapshots.

The `snapshots.pattern` option takes a Pongo2 template string to format the snapshot name.

To add a time stamp to the snapshot name, use the Pongo2 context variable `creation_date`.
Make sure to format the date in your template string to avoid forbidden characters in the snapshot name.
For example, set `snapshots.pattern` to `{{ creation_date|date:'2006-01-02_15-04-05' }}` to name the snapshots after their time of creation, down to the precision of a second.

Another way to avoid name collisions is to use the placeholder `%d` in the pattern.
For the first snapshot, the placeholder is replaced with `0`.
For subsequent snapshots, the existing snapshot names are taken into account to find the highest number at the placeholder's position.
This number is then incremented by one for the new name.
```

```{config:option} snapshots.schedule storage-pure-volume-conf
:condition: "custom volume"
:defaultdesc: "same as `snapshots.schedule`"
:scope: "global"
:shortdesc: "Schedule for automatic volume snapshots"
:type: "string"
Specify either a cron expression (`<minute> <hour> <dom> <month> <dow>`), a comma-separated list of schedule aliases (`@hourly`, `@daily`, `@midnight`, `@weekly`, `@monthly`, `@annually`, `@yearly`), or leave empty to disable automatic snapshots (the default).
```

```{config:option} volatile.uuid storage-pure-volume-conf
:defaultdesc: "random UUID"
:scope: "global"
:shortdesc: "The volume's UUID"
:type: "string"

```

<!-- config group storage-pure-volume-conf end -->
<!-- config group storage-zfs-bucket-conf start -->
```{config:option} size storage-zfs-bucket-conf
:condition: "appropriate driver"
Expand Down
35 changes: 18 additions & 17 deletions doc/reference/storage_drivers.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ storage_cephfs
storage_cephobject
storage_ceph
storage_powerflex
storage_pure
storage_dir
storage_lvm
storage_zfs
Expand All @@ -27,23 +28,23 @@ See the corresponding pages for driver-specific information and configuration op

Where possible, LXD uses the advanced features of each storage system to optimize operations.

Feature | Directory | Btrfs | LVM | ZFS | Ceph RBD | CephFS | Ceph Object | Dell PowerFlex
:--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :---
{ref}`storage-optimized-image-storage` | ❌ | ✅ | ✅ | ✅ | ✅ | ➖ | ➖ | ❌
Optimized instance creation | ❌ | ✅ | ✅ | ✅ | ✅ | ➖ | ➖ | ❌
Optimized snapshot creation | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ | ✅
Optimized image transfer | ❌ | ✅ | ❌ | ✅ | ✅ | ➖ | ➖ | ❌
Optimized backup (import/export) | ❌ | ✅ | ❌ | ✅ | ❌ | ➖ | ➖ | ❌
{ref}`storage-optimized-volume-transfer` | ❌ | ✅ | ❌ | ✅ | ✅[^1] | ➖ | ➖ | ❌
{ref}`storage-optimized-volume-refresh` | ❌ | ✅ | ✅[^2] | ✅ | ✅[^3] | ➖ | ➖ | ❌
Copy on write | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ | ✅
Block based | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ➖ | ✅
Instant cloning | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ | ❌
Storage driver usable inside a container | ✅ | ✅ | ❌ | ✅[^4] | ❌ | ➖ | ➖ | ❌
Restore from older snapshots (not latest) | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ➖ | ✅
Storage quotas | ✅[^5] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅
Available on `lxd init` | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌
Object storage | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌
Feature | Directory | Btrfs | LVM | ZFS | Ceph RBD | CephFS | Ceph Object | Dell PowerFlex | Pure Storage
:--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :---
{ref}`storage-optimized-image-storage` | ❌ | ✅ | ✅ | ✅ | ✅ | ➖ | ➖ | ❌ | ✅
Optimized instance creation | ❌ | ✅ | ✅ | ✅ | ✅ | ➖ | ➖ | ❌ | ✅
Optimized snapshot creation | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ | ✅ | ✅
Optimized image transfer | ❌ | ✅ | ❌ | ✅ | ✅ | ➖ | ➖ | ❌ | ✅
Optimized backup (import/export) | ❌ | ✅ | ❌ | ✅ | ❌ | ➖ | ➖ | ❌ | ❌
{ref}`storage-optimized-volume-transfer` | ❌ | ✅ | ❌ | ✅ | ✅[^1] | ➖ | ➖ | ❌ | ❌
{ref}`storage-optimized-volume-refresh` | ❌ | ✅ | ✅[^2] | ✅ | ✅[^3] | ➖ | ➖ | ❌ | ❌
Copy on write | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ | ✅ | ✅
Block based | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ➖ | ✅ | ✅
Instant cloning | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ➖ | ❌ | ✅
Storage driver usable inside a container | ✅ | ✅ | ❌ | ✅[^4] | ❌ | ➖ | ➖ | ❌ | ❌
Restore from older snapshots (not latest) | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ➖ | ✅ | ✅
Storage quotas | ✅[^5] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅
Available on `lxd init` | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌
Object storage | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌

[^1]: Volumes of type `block` will fall back to non-optimized transfer when migrating to an older LXD server that doesn't yet support the `RBD_AND_RSYNC` migration type.
[^2]: Requires {config:option}`storage-lvm-pool-conf:lvm.use_thinpool` to be enabled. Only when refreshing local volumes.
Expand Down
Loading

0 comments on commit fb787af

Please sign in to comment.