Skip to content

Commit

Permalink
feat(controller): patch CRDs to upgrade them
Browse files Browse the repository at this point in the history
Signed-off-by: Niladri Halder <niladri.halder26@gmail.com>
  • Loading branch information
niladrih committed Jul 26, 2023
1 parent 35e06fd commit 6f99521
Show file tree
Hide file tree
Showing 8 changed files with 2,231 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ informer:
manifests:
@echo "+ Generating zfs localPV crds"
$(PWD)/buildscripts/generate-manifests.sh
for file in volume snapshot restore;do cp ./deploy/yamls/zfs"$$file"-crd.yaml ./pkg/patcher/;done

helm:
@echo "+ Copying generated CRDs to helm charts"
Expand Down
35 changes: 35 additions & 0 deletions pkg/driver/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ package driver

import (
"fmt"
"github.com/openebs/zfs-localpv/pkg/patcher"
"k8s.io/apimachinery/pkg/runtime/schema"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -85,6 +87,39 @@ func NewController(d *CSIDriver) csi.ControllerServer {
}

func (cs *controller) init() error {
// CRD upgrade
// Ref: https://github.com/openebs/zfs-localpv/pull/439
// Ref: https://github.com/openebs/zfs-localpv/pull/457
crdGvr := schema.GroupVersionResource{
Group: "apiextensions.k8s.io",
Version: "v1",
Resource: "CustomResourceDefinition",
}

oldCrd, _ := patcher.OldZfsVolumesCrd()
newCrd, _ := patcher.NewZfsVolumesCrd()
patcher.PatchCrdOrIgnore(crdGvr, "").WithMergePatchFrom(
"zfsvolumes.zfs.openebs.io",
oldCrd,
newCrd,
)

oldCrd, _ = patcher.OldZfsSnapshotsCrd()
newCrd, _ = patcher.NewZfsSnapshotsCrd()
patcher.PatchCrdOrIgnore(crdGvr, "").WithMergePatchFrom(
"zfssnapshots.zfs.openebs.io",
oldCrd,
newCrd,
)

oldCrd, _ = patcher.OldZfsRestoresCrd()
newCrd, _ = patcher.NewZfsRestoresCrd()
patcher.PatchCrdOrIgnore(crdGvr, "").WithMergePatchFrom(
"zfsrestores.zfs.openebs.io",
oldCrd,
newCrd,
)

cfg, err := k8sapi.Config().Get()
if err != nil {
return errors.Wrapf(err, "failed to build kubeconfig")
Expand Down
27 changes: 27 additions & 0 deletions pkg/patcher/newcrd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package patcher

import (
_ "embed"
"sigs.k8s.io/yaml"
)

//go:embed zfsvolume-crd.yaml
var vol []byte

//go:embed zfssnapshot-crd.yaml
var snap []byte

//go:embed zfsrestore-crd.yaml
var res []byte

func NewZfsVolumesCrd() ([]byte, error) {
return yaml.YAMLToJSON(vol)
}

func NewZfsSnapshotsCrd() ([]byte, error) {
return yaml.YAMLToJSON(snap)
}

func NewZfsRestoresCrd() ([]byte, error) {
return yaml.YAMLToJSON(res)
}
1,045 changes: 1,045 additions & 0 deletions pkg/patcher/oldcrd.go

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions pkg/patcher/patcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package patcher

import (
"context"
"fmt"
"github.com/openebs/lib-csi/pkg/common/errors"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
k8stypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
)

type Patchable struct {
inner dynamic.NamespaceableResourceInterface
}

func PatchCrdOrIgnore(gvr schema.GroupVersionResource, namespace string) *Patchable {
cfg, err := rest.InClusterConfig()
if err != nil {
errors.Errorf("failed to generate in-cluster config: %s", err.Error())
return nil
}

client, err := dynamic.NewForConfig(cfg)
if err != nil {
errors.Errorf("failed to generate in-cluster kubernetes client: %s", err.Error())
return nil
}

return &Patchable{client.Resource(gvr)}
}

func (p *Patchable) WithMergePatchFrom(name string, original, modified []byte) {
if p == nil {
return
}

patch, err := strategicpatch.CreateTwoWayMergePatch(original, modified, apiextensions.CustomResourceDefinition{})
if err != nil {
errors.Errorf("failed to create merge patch for %s: %s", name, err.Error())
return
}
_, err = p.inner.Patch(context.TODO(), name, k8stypes.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
errors.Errorf("failed to patch resource %s: %s", name, err.Error())
return
}

fmt.Printf("successfully patched CRD %s\n", name)
}
238 changes: 238 additions & 0 deletions pkg/patcher/zfsrestore-crd.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@


##############################################
########### ############
########### ZFSRestore CRD ############
########### ############
##############################################

# ZFSRestores CRD is autogenerated via `make manifests` command.
# Do the modification in the code and run the `make manifests` command
# to generate the CRD definition

---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.1
creationTimestamp: null
name: zfsrestores.zfs.openebs.io
spec:
group: zfs.openebs.io
names:
kind: ZFSRestore
listKind: ZFSRestoreList
plural: zfsrestores
singular: zfsrestore
scope: Namespaced
versions:
- name: v1
schema:
openAPIV3Schema:
description: ZFSRestore describes a cstor restore resource created as a custom
resource
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: ZFSRestoreSpec is the spec for a ZFSRestore resource
properties:
ownerNodeID:
description: owner node name where restore volume is present
minLength: 1
type: string
restoreSrc:
description: it can be ip:port in case of restore from remote or volumeName
in case of local restore
minLength: 1
pattern: ^([0-9]+.[0-9]+.[0-9]+.[0-9]+:[0-9]+)$
type: string
volumeName:
description: volume name to where restore has to be performed
minLength: 1
type: string
required:
- ownerNodeID
- restoreSrc
- volumeName
type: object
status:
description: ZFSRestoreStatus is to hold result of action.
enum:
- Init
- Done
- Failed
- Pending
- InProgress
- Invalid
type: string
volSpec:
description: VolumeInfo defines ZFS volume parameters for all modes in
which ZFS volumes can be created like - ZFS volume with filesystem,
ZFS Volume exposed as zfs or ZFS volume exposed as raw block device.
Some of the parameters can be only set during creation time (as specified
in the details of the parameter), and a few are editable. In case of
Cloned volumes, the parameters are assigned the same values as the source
volume.
properties:
capacity:
description: Capacity of the volume
minLength: 1
type: string
compression:
description: 'Compression specifies the block-level compression algorithm
to be applied to the ZFS Volume. The value "on" indicates ZFS to
use the default compression algorithm. The default compression algorithm
used by ZFS will be either lzjb or, if the lz4_compress feature
is enabled, lz4. Compression property can be edited after the volume
has been created. The change will only be applied to the newly-written
data. For instance, if the Volume was created with "off" and the
next day the compression was modified to "on", the data written
prior to setting "on" will not be compressed. Default Value: off.'
pattern: ^(on|off|lzjb|zstd|gzip|gzip-[1-9]|zle|lz4|halder)$
type: string
dedup:
description: 'Deduplication is the process for removing redundant
data at the block level, reducing the total amount of data stored.
If a file system has the dedup property enabled, duplicate data
blocks are removed synchronously. The result is that only unique
data is stored and common components are shared among files. Deduplication
can consume significant processing power (CPU) and memory as well
as generate additional disk IO. Before creating a pool with deduplication
enabled, ensure that you have planned your hardware requirements
appropriately and implemented appropriate recovery practices, such
as regular backups. As an alternative to deduplication consider
using compression=lz4, as a less resource-intensive alternative.
should be enabled on the zvol. Dedup property can be edited after
the volume has been created. Default Value: off.'
enum:
- "on"
- "off"
type: string
encryption:
description: 'Enabling the encryption feature allows for the creation
of encrypted filesystems and volumes. ZFS will encrypt file and
zvol data, file attributes, ACLs, permission bits, directory listings,
FUID mappings, and userused / groupused data. ZFS will not encrypt
metadata related to the pool structure, including dataset and snapshot
names, dataset hierarchy, properties, file size, file holes, and
deduplication tables (though the deduplicated data itself is encrypted).
Default Value: off.'
pattern: ^(on|off|aes-128-[c,g]cm|aes-192-[c,g]cm|aes-256-[c,g]cm)$
type: string
fsType:
description: 'FsType specifies filesystem type for the zfs volume/dataset.
If FsType is provided as "zfs", then the driver will create a ZFS
dataset, formatting is not required as underlying filesystem is
ZFS anyway. If FsType is ext2, ext3, ext4 or xfs, then the driver
will create a ZVOL and format the volume accordingly. FsType can
not be modified once volume has been provisioned. Default Value:
ext4.'
type: string
keyformat:
description: KeyFormat specifies format of the encryption key The
supported KeyFormats are passphrase, raw, hex.
enum:
- passphrase
- raw
- hex
type: string
keylocation:
description: KeyLocation is the location of key for the encryption
type: string
ownerNodeID:
description: OwnerNodeID is the Node ID where the ZPOOL is running
which is where the volume has been provisioned. OwnerNodeID can
not be edited after the volume has been provisioned.
minLength: 1
type: string
poolName:
description: poolName specifies the name of the pool where the volume
has been created. PoolName can not be edited after the volume has
been provisioned.
minLength: 1
type: string
recordsize:
description: 'Specifies a suggested block size for files in the file
system. The size specified must be a power of two greater than or
equal to 512 and less than or equal to 128 Kbytes. RecordSize property
can be edited after the volume has been created. Changing the file
system''s recordsize affects only files created afterward; existing
files are unaffected. Default Value: 128k.'
minLength: 1
type: string
shared:
description: Shared specifies whether the volume can be shared among
multiple pods. If it is not set to "yes", then the ZFS-LocalPV Driver
will not allow the volumes to be mounted by more than one pods.
enum:
- "yes"
- "no"
type: string
snapname:
description: SnapName specifies the name of the snapshot where the
volume has been cloned from. Snapname can not be edited after the
volume has been provisioned.
type: string
thinProvision:
description: 'ThinProvision describes whether space reservation for
the source volume is required or not. The value "yes" indicates
that volume should be thin provisioned and "no" means thick provisioning
of the volume. If thinProvision is set to "yes" then volume can
be provisioned even if the ZPOOL does not have the enough capacity.
If thinProvision is set to "no" then volume can be provisioned only
if the ZPOOL has enough capacity and capacity required by volume
can be reserved. ThinProvision can not be modified once volume has
been provisioned. Default Value: no.'
enum:
- "yes"
- "no"
type: string
volblocksize:
description: 'VolBlockSize specifies the block size for the zvol.
The volsize can only be set to a multiple of volblocksize, and cannot
be zero. VolBlockSize can not be edited after the volume has been
provisioned. Default Value: 8k.'
minLength: 1
type: string
volumeType:
description: volumeType determines whether the volume is of type "DATASET"
or "ZVOL". If fstype provided in the storageclass is "zfs", a volume
of type dataset will be created. If "ext4", "ext3", "ext2" or "xfs"
is mentioned as fstype in the storageclass, then a volume of type
zvol will be created, which will be further formatted as the fstype
provided in the storageclass. VolumeType can not be modified once
volume has been provisioned.
enum:
- ZVOL
- DATASET
type: string
required:
- capacity
- ownerNodeID
- poolName
- volumeType
type: object
required:
- spec
- status
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
Loading

0 comments on commit 6f99521

Please sign in to comment.