Extend CSI snapshot to support Longhorn BackingImage
## Summary
In Longhorn, we have BackingImage for VM usage. We would like to extend the CSI Snapshotter to support BackingImage management.
### Related Issues
[BackingImage Management via VolumeSnapshot #5005](https://github.com/longhorn/longhorn/issues/5005)
## Motivation
### Goals
Extend the CSI snapshotter to support:
- Create Longhorn BackingImage
- Delete Longhorn BackingImage
- Creating a new PVC from CSI snapshot that is associated with a Longhorn BackingImage
### Non-goals [optional]
- Can support COW over each relative base image for delta data transfer for better space efficiency. (Will be in next improvement)
- User can backup a BackingImage based volume and restore it in another cluster without manually preparing BackingImage in a new cluster.
## Proposal
### User Story
With this improvement, users can use standard CSI VolumeSnapshot as the unified interface for BackingImage creation, deletion and restoration of a Volume.
### User Experience In Detail
To use this feature, users need to deploy the CSI snapshot CRDs and related Controller
1. The instructions are already on our document: https://longhorn.io/docs/1.4.1/snapshots-and-backups/csi-snapshot-support/enable-csi-snapshot-support/
2. Create a VolumeSnapshotClass with type `bi` which refers to BackingImage
```yaml
kind: VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
metadata:
name: longhorn-snapshot-vsc
driver: driver.longhorn.io
deletionPolicy: Delete
parameters:
type: bi
export-type: qcow2 # default to raw if it is not provided
```
#### BackingImage creation via VolumenSnapshot resource
Users can create a BackingImage of a Volume by creation of VolumeSnapshot. Example below for a Volume named `test-vol`
```yaml
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
name: test-snapshot-backing
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
source:
persistentVolumeClaimName: test-vol
```
Longhorn will create a BackingImage **exported** from this Volume.
#### Restoration via VolumeSnapshot resource
Users can create a volume based on a prior created VolumeSnapshot. Example below for a Volume named `test-vol-restore`
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-vol-restore
spec:
storageClassName: longhorn
dataSource:
name: test-snapshot-backing
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
```
Longhorn will create a Volume based on the BackingImage associated with the VolumeSnapshot.
#### Restoration of an existing BackingImage (pre-provisioned)
Users can request the creation of a Volume based on a prior BackingImage which was not created via the CSI VolumeSnapshot.
With the BackingImage already existing, users need to create the VolumeSnapshotContent with an associated VolumeSnapshot. The `snapshotHandle` of the VolumeSnapshotContent needs to point to an existing BackingImage. Example below for a Volume named `test-restore-existing-backing` and an existing BackingImage `test-bi`
- For pre-provisioning, users need to provide following query parameters:
-`backingImageDataSourceType`: `sourceType` of existing BackingImage, e.g. `export-from-volume`, `download`
-`backingImage`: Name of the BackingImage
- you should also provide the `sourceParameters` of existing BackingImage in the `snapshotHandle` for validation.
-`export-from-volume`: you should provide
-`volume-name`
-`export-type`
-`download`: you should proviide
-`url`
-`checksum`: optional
```yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotContent
metadata:
name: test-existing-backing
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
driver: driver.longhorn.io
deletionPolicy: Delete
source:
# NOTE: change this to point to an existing BackingImage in Longhorn
Longhorn will create a Volume based on the BackingImage associated with the VolumeSnapshot and the VolumeSnapshotContent.
#### Restoration of a non-existing BackingImage (on-demand provision)
Users can request the creation of a Volume based on a BackingImage which was not created yet with following 2 kinds of data sources.
1.`download`: Download a file from a URL as a BackingImage.
2.`export-from-volume`: Export an existing in-cluster volume as a backing image.
Users need to create the VolumeSnapshotContent with an associated VolumeSnapshot. The `snapshotHandle` of the VolumeSnapshotContent needs to provide the parameters for the data source. Example below for a volume named `test-on-demand-backing` and an non-existing BackingImage `test-bi` with two different data sources.
1.`download`: Users need to provide following parameters
-`backingImageDataSourceType`: `download` for on-demand download.
-`backingImage`: Name of the BackingImage
-`url`: The file from a URL as a BackingImage.
-`backingImageChecksum`: Optional. Used for checking the checksum of the file.
- example yaml:
```yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotContent
metadata:
name: test-on-demand-backing
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
driver: driver.longhorn.io
deletionPolicy: Delete
source:
# NOTE: change this to provide the correct parameters
Users then can create corresponding VolumeSnapshot and PVC
```yaml
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
name: test-snapshot-on-demand-backing
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
source:
# NOTE: change this to point to the prior VolumeSnapshotContent
volumeSnapshotContentName: test-on-demand-backing
```
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-restore-on-demand-backing
spec:
storageClassName: longhorn
dataSource:
name: test-snapshot-on-demand-backing
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
```
### API changes
No changes necessary
## Design
### Implementation Overview
We add a new type `bi` to the parameter `type` in the VolumeSnapshotClass. It means that the CSI VolumeSnapshot created with this VolumeSnapshotClass is associated with a Longhorn BackingImage.
#### CreateSnapshot function
When the users create VolumeSnapshot and the volumeSnapshotClass `type` is `bi`
```yaml
apiVersion: snapshot.storage.k8s.io/v1beta1
kind: VolumeSnapshot
metadata:
name: test-snapshot-backing
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
source:
persistentVolumeClaimName: test-vol
```
We do:
- Get the name of the Volume
- The name of the BackingImage will be same as the VolumeSnapshot `test-snapshot-backing`.
- Check if a BackingImage with the same name as the requested VolumeSnapshot already exists. Return success without creating a new BackingImage.
- Create a BackingImage.
- Get `export-type` from VolumeSnapshotClass parameter `export-type`, default to `raw.`
- Encode the `snapshotId` as `bi://backing?backingImageDataSourceType=export-from-volume&backingImage=test-snapshot-backing&volume-name=${VolumeName}&export-type=raw`
- This `snaphotId` will be used in the later CSI CreateVolume and DeleteSnapshot call.
#### CreateVolume function
- If VolumeSource type is `VolumeContentSource_Snapshot`, decode the `snapshotId` to get the parameters.
- If BackingImage with the given name already exists, create the volume.
- If BackingImage with the given name does not exists, we prepare it first. There are 2 kinds of types which are `export-from-volume` and `download`.
- For `download`, it means we have to prepare the BackingImage before creating the Volume. We first decode other parameters from `snapshotId` and create the BackingImage.
- For `export-from-volume`, it means we have to prepare the BackingImage before creating the Volume. We first decode other parameters from `snapshotId` and create the BackingImage.
NOTE: we already have related code for preparing the BackingImage with type `download` or `export-from-volume` before creating a Volume, [here](https://github.com/longhorn/longhorn-manager/blob/master/csi/controller_server.go#L195)
#### DeleteSnapshot function
- Decode the `snapshotId` to get the name of the BackingImage. Then we delete the BackingImage directly.
### Test plan
Integration test plan.
#### Prerequisite
1. Deploy the csi snapshot CRDs, Controller as instructed at